Skip to content

Add name argument to @wp.kernel (GH-1561)#1570

Open
thomasbbrunner wants to merge 2 commits into
NVIDIA:mainfrom
thomasbbrunner:tbrunner/kernel-name
Open

Add name argument to @wp.kernel (GH-1561)#1570
thomasbbrunner wants to merge 2 commits into
NVIDIA:mainfrom
thomasbbrunner:tbrunner/kernel-name

Conversation

@thomasbbrunner

@thomasbbrunner thomasbbrunner commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Description

Addresses #1561.

@wp.kernel derives a kernel's key from make_full_qualified_name(func), which in turn uses the function's __qualname__. There's no way to override it.

The @wp.func decorator already exposes a name argument for the same purpose.

Changes

Here I'm adding support for a name argument for the wp.kernel decorator, enabling overriding the kernel's name.

I chose name to be consistent with the wp.func API. However, internally this is called key.

A potential pitfall is if the user passes a name that is not a valid C name. I've added an explicit check for this, otherwise users are faced with a somewhat cryptic compiler error.

New feature / enhancement

This is especially useful when generating kernels with the closure pattern. In this case, different kernels have the same key and only differ by their hashes:

import warp as wp

def make_scaler(factor: float) -> wp.Kernel:
    @wp.kernel
    def scale(x: wp.array(dtype=wp.float32)):
        i = wp.tid()
        x[i] = x[i] * factor
    return scale

double = make_scaler(2.0)
triple = make_scaler(3.0)

print(double.key)  # make_scaler__locals__scale
print(triple.key)  # make_scaler__locals__scale  <-- identical!

With these changes, users can now specify a name for the kernel:

def make_scaler(factor: float) -> wp.Kernel:
    @wp.kernel(name=f"scale{factor}".replace(".", "_"))
    def scale(x: wp.array(dtype=wp.float32)):
        i = wp.tid()
        x[i] = x[i] * factor
    return scale

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.
  • CHANGELOG.md is updated for any user-facing changes under the Unreleased section.

Validation summary

Ran all tests and linter.

Summary by CodeRabbit

  • New Features
    • @wp.kernel decorator now accepts an optional name argument to customize the kernel’s identifier
    • When specified, name overrides the auto-generated key
    • Invalid names raise a validation error
  • Bug Fixes
    • Kernel lookup now correctly matches renamed kernels using the stored qualified name
  • Tests
    • Added tests for kernel naming behavior, including custom names, defaults, and validation
    • Added identifier validation test coverage for valid/invalid C-identifier-like strings
    • Added tests for renamed-kernel behavior in @wp.overload stubs

Signed-off-by: Thomas B. Brunner <thomas.brunner@helsing.ai>
@copy-pr-bot

copy-pr-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Enterprise

Run ID: 5c24a495-62f3-40f6-9076-18562d859a83

📥 Commits

Reviewing files that changed from the base of the PR and between 013f483 and 475d142.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • warp/_src/context.py
  • warp/tests/test_generics.py
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

Adds a name keyword argument to the @wp.kernel decorator that overrides the kernel's key. A new is_valid_c_identifier() helper (backed by a compiled regex) validates the supplied name and raises ValueError if invalid. The kernel decorator pre-computes the key based on the provided name or qualified function name and passes it to the Kernel constructor, which stores the original qualified name for fallback lookup in Module._find_kernel.

Changes

@wp.kernel name override

Layer / File(s) Summary
C-identifier validator
warp/_src/codegen.py, warp/tests/test_codegen.py
Adds _C_IDENTIFIER_RE compiled regex and is_valid_c_identifier(name: str) -> bool function. Unit test verifies valid identifiers and rejects empty strings, leading digits, whitespace, special characters, and non-ASCII.
@wp.kernel name parameter
warp/_src/context.py
Adds `name: str
Kernel storage and fallback lookup
warp/_src/context.py
Kernel.init stores the Python function's qualified name in a new qualname attribute and uses it to set the default key. Module._find_kernel implements a fallback lookup: after the fast path fails, it scans registered kernels and returns the most recently registered kernel whose qualname matches the lookup key.
Kernel naming behavior tests
warp/tests/test_context.py
Three tests validate that the name parameter works: override test verifies the key equals the provided name, default test verifies the key ends with the function name when name is omitted, and invalid-name test verifies ValueError is raised with an appropriate error message.
Overload and closure scenario tests
warp/tests/test_generics.py
Tests verify that kernel naming works with overloads and closures. One test checks a renamed kernel bound to overload stubs; another verifies that a closure factory producing separately named kernels results in distinct keys and correct overload counts.
Changelog
CHANGELOG.md
Records the new name argument for @wp.kernel in the Unreleased Added section, noting it overrides the kernel's generated key and referencing GH-1561.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • Allow passing a key/name to the @wp.kernel #1561: This PR implements exactly the feature described in that issue — adding a name argument to @wp.kernel that overrides the kernel's generated key with C-identifier validation — and the changelog explicitly references it.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main feature being added: the name argument to @wp.kernel, with direct reference to the issue (GH-1561).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds an optional name argument to the @wp.kernel decorator, enabling callers to override the auto-generated key that is otherwise derived from the function's __qualname__. This mirrors the existing name parameter on @wp.func and is particularly useful for the closure/factory pattern where multiple kernels share the same Python qualified name.

  • warp/_src/codegen.py gains is_valid_c_identifier() (regex-based) and _find_kernel() in Module is extended with an O(n) fallback that matches renamed kernels by their stored qualname attribute, returning the most-recently-registered kernel to support in-closure @wp.overload usage.
  • warp/_src/context.py stores self.qualname on every Kernel object and validates the user-supplied name before creating the kernel; @wp.overload already works through the updated _find_kernel.
  • Tests in test_context.py, test_codegen.py, and test_generics.py cover name override, default naming, invalid names, and overload interaction including the renamed-closure pattern.

Confidence Score: 5/5

Safe to merge — the change is additive, validation is in place, and the overload-lookup fallback is well-tested including the closure pattern.

The new name parameter is keyword-only, defaults to None (preserving existing behaviour), and is validated before reaching any code-generation path. The qualname attribute stored on every Kernel object is a clean solution for the @wp.overload fallback lookup. Tests cover the main paths — default naming, custom naming, invalid names, and the renamed-closure overload scenario that motivated the feature.

No files require special attention.

Important Files Changed

Filename Overview
warp/_src/context.py Adds name parameter to kernel(), validates it via is_valid_c_identifier, stores qualname on every Kernel, and extends _find_kernel with an insertion-order fallback for renamed kernels.
warp/_src/codegen.py Adds _C_IDENTIFIER_RE regex and is_valid_c_identifier() helper; straightforward and well-tested.
warp/tests/test_context.py New tests for name override, default naming, and invalid-name ValueError — good coverage of the happy/sad paths.
warp/tests/test_generics.py Adds test_overload_with_renamed_kernel and test_overload_renamed_kernel_closure to verify @wp.overload still binds correctly after a kernel is renamed, including the closure/factory pattern.
warp/tests/test_codegen.py Adds test_is_valid_c_identifier covering valid identifiers and common invalid cases; clean and correct.
CHANGELOG.md Adds a user-facing entry under the Unreleased section as required by the contributing guide.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["@wp.kernel decorator"] --> B{name provided?}
    B -- No --> C["key = qualified name of func"]
    B -- Yes --> D{valid C identifier?}
    D -- No --> E["raise ValueError"]
    D -- Yes --> F["key = name"]
    C --> G["Kernel.__init__"]
    F --> G
    G --> H["store self.qualname = qualified name"]
    H --> I["store self.key = key"]
    I --> J["module.kernels[key] = self"]

    K["@wp.overload as decorator"] --> L["module._find_kernel(fn)"]
    L --> M["compute fn qualname"]
    M --> N{kernel keyed by qualname exists?}
    N -- Yes --> O["return kernel"]
    N -- No --> P["scan all kernels by .qualname attr"]
    P --> Q["return last matching kernel"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["@wp.kernel decorator"] --> B{name provided?}
    B -- No --> C["key = qualified name of func"]
    B -- Yes --> D{valid C identifier?}
    D -- No --> E["raise ValueError"]
    D -- Yes --> F["key = name"]
    C --> G["Kernel.__init__"]
    F --> G
    G --> H["store self.qualname = qualified name"]
    H --> I["store self.key = key"]
    I --> J["module.kernels[key] = self"]

    K["@wp.overload as decorator"] --> L["module._find_kernel(fn)"]
    L --> M["compute fn qualname"]
    M --> N{kernel keyed by qualname exists?}
    N -- Yes --> O["return kernel"]
    N -- No --> P["scan all kernels by .qualname attr"]
    P --> Q["return last matching kernel"]
Loading

Reviews (2): Last reviewed commit: "Handle renamed kernels and wp.overload" | Re-trigger Greptile

Comment thread warp/_src/codegen.py
Comment on lines +5138 to +5139
def is_valid_c_identifier(name: str) -> bool:
return _C_IDENTIFIER_RE.match(name) is not None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Reserved C/C++ keywords pass validation

is_valid_c_identifier only checks the structural regex pattern — it accepts any syntactically valid identifier, including C reserved words (int, float, void, if, for, while, return, struct, etc.) and CUDA built-ins (threadIdx, blockDim, etc.). A user who calls @wp.kernel(name="int") will pass this check but still get a cryptic compiler error, which is the exact failure mode this check was added to prevent.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@warp/_src/codegen.py`:
- Around line 5135-5139: The is_valid_c_identifier function currently only
validates the syntactic shape of identifiers using regex pattern matching, but
fails to reject reserved C/C++ keywords like "for", "class", "int", and "return"
which are syntactically valid identifiers but cannot be used as function
identifiers in generated C/CUDA code. Add a check within is_valid_c_identifier
to verify that the name is not a C/C++ reserved keyword by comparing it against
a comprehensive set of reserved keywords, and return False if the name matches
any keyword before returning the regex match result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Enterprise

Run ID: 63571386-5138-4cd6-adc4-1cd1135347c2

📥 Commits

Reviewing files that changed from the base of the PR and between 7a57d68 and 013f483.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • warp/_src/codegen.py
  • warp/_src/context.py
  • warp/tests/test_codegen.py
  • warp/tests/test_context.py

Comment thread warp/_src/codegen.py
Comment on lines +5135 to +5139
_C_IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")


def is_valid_c_identifier(name: str) -> bool:
return _C_IDENTIFIER_RE.match(name) is not None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Are reserved C/C++ keywords (for example for, while, class, template) legal identifiers for function names?

💡 Result:

No, reserved C/C++ keywords (such as for, while, class, and template) are not legal identifiers for function names [1][2][3]. In C and C++, keywords are reserved by the language specification to provide specific syntactic and semantic meaning to the compiler [1][4]. Because these terms are essential to the language's core structures, they cannot be redefined, overloaded, or used as names for identifiers such as functions, variables, classes, or templates [1][2][5]. The only exception to this rule is the use of these tokens within an attribute-token context (introduced in C++11), where they are not treated as reserved keywords [1][4]. Attempting to use a keyword as a function name will result in a compilation error [3]. Furthermore, beyond explicit keywords, certain other identifiers are reserved for use by the implementation (such as those containing a double underscore or beginning with an underscore followed by an uppercase letter), and using these as function names can lead to undefined behavior [1][2][6].

Citations:


🏁 Script executed:

# Check the current code at the specified location
head -5140 warp/_src/codegen.py | tail -15

Repository: NVIDIA/warp

Length of output: 572


🏁 Script executed:

# Search for any existing reserved keyword handling in codegen.py
rg -n "keyword|reserved|RESERVED" warp/_src/codegen.py | head -20

Repository: NVIDIA/warp

Length of output: 883


🏁 Script executed:

# Check if this validator is used for kernel names or function validation
rg -n "is_valid_c_identifier\|_C_IDENTIFIER_RE" warp/_src/codegen.py

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# The is_valid_c_identifier might not be in use yet. Let's check if it's called anywhere
rg "is_valid_c_identifier" warp/_src/

Repository: NVIDIA/warp

Length of output: 209


🏁 Script executed:

# Check if there's any validation of kernel names in the kernel decorator or related code
rg -n "def kernel\|`@kernel`" warp/_src/codegen.py | head -10

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Search for where kernel names are processed or validated
rg -n "name=" warp/_src/codegen.py | grep -i "kernel\|func" | head -15

Repository: NVIDIA/warp

Length of output: 952


🏁 Script executed:

# Check where is_valid_c_identifier is called in context.py and what it validates
rg -B 5 -A 5 "is_valid_c_identifier" warp/_src/context.py

Repository: NVIDIA/warp

Length of output: 492


🏁 Script executed:

# Also check the kernel decorator implementation to understand the kernel name validation flow
fd "kernel.py\|__init__.py" warp/_src/ --type f | head -5

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Check if there's any existing keyword filtering or handling anywhere in warp codebase
rg -i "keyword|reserved" warp/_src/ --type py | grep -v "\.pyc" | head -20

Repository: NVIDIA/warp

Length of output: 2137


🏁 Script executed:

# Look at the make_full_qualified_name function to understand how kernel names are generated
rg -B 3 -A 8 "make_full_qualified_name" warp/_src/codegen.py

Repository: NVIDIA/warp

Length of output: 473


🏁 Script executed:

# Check C/C++ codegen targets to understand which keywords Warp needs to avoid
rg -n "cuda\|c_\+\+\|CPP\|GLSL" warp/_src/codegen.py | grep -i "target\|backend\|language" | head -10

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Check if Warp targets CUDA or other languages beyond C/C++
rg -n "class.*CodeGen\|def.*codegen" warp/_src/codegen.py | head -10

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Verify if CUDA has additional reserved keywords beyond C++
web_search
CUDA C/C++ reserved keywords additional to C++ standard

Repository: NVIDIA/warp

Length of output: 149


🏁 Script executed:

# Check if there are existing tests for identifier validation
fd "test.*codegen\|test.*kernel" warp/tests/ --type f

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Find test files related to codegen or kernel
find warp/tests -name "*test*codegen*" -o -name "*test*kernel*" | head -10

Repository: NVIDIA/warp

Length of output: 294


🏁 Script executed:

# Check if there are existing tests that might validate identifier handling
rg "is_valid_c_identifier\|_C_IDENTIFIER_RE" warp/tests/

Repository: NVIDIA/warp

Length of output: 37


🌐 Web query:

CUDA C reserved keywords beyond C standard library

💡 Result:

In CUDA C/C++ (as implemented by nvcc), the main “reserved keywords beyond the C standard library” are the CUDA language extension keywords/specifiers—i.e., identifiers starting with double underscores that nvcc recognizes and gives special meaning. Key CUDA-reserved specifiers (language extensions) documented by NVIDIA include: - host / device / global (execution space specifiers for where code runs, or to declare kernels) [1] - restrict (pointer restrict qualifier) [2][1] - launch_bounds (function qualifier for launch bounds on global functions) [2][1] - grid_constant (qualifier for parameters) [2][1] - noinline, forceinline, inline_hint (inlining control qualifiers) [2][1] - cluster_dims (cluster dimensions qualifier) [2][1] - device, constant, shared, managed (memory-space/storage specifiers for variables) [1] Additionally, NVIDIA’s CUDA programming guide documents that CUDA source files use these extensions and that any source file containing CUDA extensions must be compiled with nvcc. [3]

Citations:


🏁 Script executed:

# Check test_codegen.py for any identifier validation tests
rg -n "is_valid_c_identifier\|C_IDENTIFIER" warp/tests/test_codegen.py

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Look at test_codegen.py to understand what's already tested
head -100 warp/tests/test_codegen.py

Repository: NVIDIA/warp

Length of output: 1991


🏁 Script executed:

# Check if there are any actual kernel name validations in tests
rg -B 3 -A 3 "name.*=.*`@wp`\.kernel\|`@wp`\.kernel.*name" warp/tests/ | head -30

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Let's check the context where the validator is used to understand the full picture
rg -B 10 -A 5 "is_valid_c_identifier" warp/_src/context.py

Repository: NVIDIA/warp

Length of output: 582


🏁 Script executed:

# Verify there are no existing keyword checks elsewhere in the kernel path
rg -n "keyword\|reserved.*keyword" warp/_src/context.py

Repository: NVIDIA/warp

Length of output: 37


🏁 Script executed:

# Check what happens when a keyword is used as kernel name currently
rg -n "ValueError.*valid.*C.*identifier" warp/_src/

Repository: NVIDIA/warp

Length of output: 192


Reject reserved C/C++ keywords in the identifier validator

Line 5138 currently accepts keyword tokens like for/class because it only checks identifier shape. Those are invalid function identifiers in generated C/CUDA code and will fail at compile time, defeating the purpose of early validation.

Proposed fix
 _C_IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
+_C_RESERVED_KEYWORDS = {
+    # include the full C/C++ keyword set used by Warp codegen targets
+    "auto", "break", "case", "char", "const", "continue", "default", "do",
+    "double", "else", "enum", "extern", "float", "for", "goto", "if", "int",
+    "long", "register", "return", "short", "signed", "sizeof", "static",
+    "struct", "switch", "typedef", "union", "unsigned", "void", "volatile",
+    "while", "class", "namespace", "template", "typename",
+}
 
 
 def is_valid_c_identifier(name: str) -> bool:
-    return _C_IDENTIFIER_RE.match(name) is not None
+    return _C_IDENTIFIER_RE.fullmatch(name) is not None and name not in _C_RESERVED_KEYWORDS
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@warp/_src/codegen.py` around lines 5135 - 5139, The is_valid_c_identifier
function currently only validates the syntactic shape of identifiers using regex
pattern matching, but fails to reject reserved C/C++ keywords like "for",
"class", "int", and "return" which are syntactically valid identifiers but
cannot be used as function identifiers in generated C/CUDA code. Add a check
within is_valid_c_identifier to verify that the name is not a C/C++ reserved
keyword by comparing it against a comprehensive set of reserved keywords, and
return False if the name matches any keyword before returning the regex match
result.

@shi-eric shi-eric requested a review from c0d1f1ed June 21, 2026 04:25
Comment thread warp/_src/context.py
else:
if not warp._src.codegen.is_valid_c_identifier(name):
raise ValueError(f"@wp.kernel for '{f.__name__}': name '{name}' is not a valid C identifier.")
key = name

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please fix decorator-form @wp.overload with renamed generic kernels.

This branch registers a kernel only under the explicit name= key, but the documented overload-stub path still resolves the kernel from the stub's Python qualified name via Module._find_kernel(). That means this now fails:

from typing import Any

import warp as wp


@wp.kernel(name="custom_scale")
def scale(x: wp.array[Any], s: Any):
    i = wp.tid()
    x[i] = s * x[i]


@wp.overload
def scale(x: wp.array[wp.float32], s: wp.float32):
    ...

Observed on this branch:

RuntimeError: Failed to find a kernel named 'scale' in module __main__

Direct overload registration still works:

wp.overload(scale, [wp.array[wp.float32], wp.float32])

so the regression is specifically in the decorator-form lookup. I think the fix should preserve lookup by the original Python qualified name, or otherwise teach _find_kernel() / @wp.overload how to find kernels whose key was overridden by @wp.kernel(name=...).

Please also add a regression test covering @wp.kernel(name="...") plus decorator-form @wp.overload.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Indeed, thanks for spotting this issue.

From looking at the code, there are a couple ways to address this. I took the liberty of implementing one of them.

For completeness, these are the options considered:

  1. Key self.kernels by kernel.qualname instead of kernel.key. This makes the _find_kernel() implementation pretty simple, but messes with the AOT and causes collisions deeper in the code. Not really a valid solution.
  2. Store the kernel.qualname next to kernel.key. If _find_kernel fails to find a kernel from the func's qualname, assume it was renamed. Then iterate over the kernels in the module, and compare the qualnames. This is the one implemented.
  3. Keep another dict self.kernels_by_qualname next to self.kernels in the Module class. _find_kernel() uses this other dict. Drawback is that we need to keep these two data structures in sync.

Open to iterating over this.

Comment thread CHANGELOG.md Outdated
Comment on lines +7 to +8
- Add a `name` argument to `@wp.kernel` to override the kernel's key, mirroring `@wp.func`.
([GH-1561](https://github.com/NVIDIA/warp/issues/1561)).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nitpick: Please revise the CHANGELOG.md entry to avoid saying this mirrors @wp.func.

@wp.func(name=...) is useful precedent for the API shape, but the changelog should describe the kernel behavior directly rather than compare it to a different decorator.

Suggested wording:

Add a `name` argument to `@wp.kernel` to override the kernel's generated key.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, done!

@thomasbbrunner

thomasbbrunner commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Added a fix for the wp.overload edge-case you highlighted, @shi-eric. Thanks for spotting it.

Now, it can happen that when using the closure pattern with wp.overload, we get multiple possible matches in _find_kernel().

For instance, in code below, the overload would find two kernels with the qualname scale when running make("b").

    def make(suffix):
        @wp.kernel(name=f"kernel_{suffix}")
        def scale(x: Any):
            return

        @wp.overload  # <-- this overload will match the first registered `scale` kernel
        def scale(x: float): ...

        return scale

    first = make("a")
    second = make("b")

I've added some logic to address this, namely, picking the last match, which should correspond to the correct target kernel.

Admittedly, this check is fragile. It assumes that the @wp.overload is defined just after the overloaded kernel, self.kernels preserves insertion order and that the self.kernels keys aren't overwritten.

Alternatively, we can raise an error if multiple matches are found. In this case, users would need to pass a custom name that is different for each closure case.

Note: I've added the fix on a separate commit for easier review. I'd squash everything before merging.

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