Skip to content

Fix loading token for TypeSpec #3189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2025

Conversation

josesimoes
Copy link
Member

@josesimoes josesimoes commented Jun 24, 2025

Description

  • Parsing a typespec when dumping an ldtoken now outputs correct type.
  • Parsing a typespec when executing ldtoken IL now sets reflection with instanciated type.
  • Add parameter with caller to SetReflection from TypeSpec.
  • Fix calls.

Motivation and Context

How Has This Been Tested?

Screenshots

Types of changes

  • Improvement (non-breaking change that improves a feature, code or algorithm)
  • Bug fix (non-breaking change which fixes an issue with code or algorithm)
  • New feature (non-breaking change which adds functionality to code)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Config and build (change in the configuration and build system, has no impact on code or features)
  • Dev Containers (changes related with Dev Containers, has no impact on code or features)
  • Dependencies/declarations (update dependencies or assembly declarations and changes associated, has no impact on code or features)
  • Documentation (changes or updates in the documentation, has no impact on code or features)

Checklist

  • My code follows the code style of this project (only if there are changes in source code).
  • My changes require an update to the documentation (there are changes that require the docs website to be updated).
  • I have updated the documentation accordingly (the changes require an update on the docs in this repo).
  • I have read the CONTRIBUTING document.
  • I have tested everything locally and all new and existing tests passed (only if there are changes in source code).

Summary by CodeRabbit

  • New Features

    • Improved handling and resolution of generic type parameters in reflection scenarios, enhancing accuracy when working with generic types.
  • Bug Fixes

    • Enhanced type name formatting and generic argument resolution during diagnostic output for better clarity.
  • Refactor

    • Updated internal interfaces for setting reflection data to support more detailed type information and context.

@josesimoes josesimoes added the Area: Interpreter Everything related with the interpreter, execution engine and such label Jun 24, 2025
Copy link

coderabbitai bot commented Jun 24, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes update the SetReflection method in CLR_RT_HeapBlock to accept a CLR_RT_TypeSpec_Instance and an optional caller type spec index, replacing the previous single-parameter version. All call sites and the method declaration are updated accordingly. Related logic for generic type parameter resolution and type name formatting is also adjusted.

Changes

File(s) Change Summary
src/CLR/Core/CLR_RT_HeapBlock.cpp Replaced SetReflection implementation to accept CLR_RT_TypeSpec_Instance and optional caller; updated logic for generic parameter resolution.
src/CLR/Include/nanoCLR_Runtime__HeapBlock.h Updated SetReflection method signature to new parameter types.
src/CLR/Core/CLR_RT_HeapBlock_Array.cpp,
src/CLR/Core/Interpreter.cpp
Updated all calls to SetReflection to use new parameters (CLR_RT_TypeSpec_Instance and caller).
src/CLR/Diagnostics/Info.cpp Adjusted type spec handling, generic parameter resolution, and type name formatting in token dumping logic.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant HeapBlock
    participant TypeSystem

    Caller->>HeapBlock: SetReflection(tsInst, caller)
    HeapBlock->>HeapBlock: Initialize as reflection type
    HeapBlock->>HeapBlock: Parse tsInst with SignatureParser
    alt First element is generic parameter
        HeapBlock->>TypeSystem: Resolve generic parameter using caller
        TypeSystem-->>HeapBlock: Return mapped type argument
        HeapBlock->>HeapBlock: Set reflection data accordingly
    else No valid caller or not generic parameter
        HeapBlock->>HeapBlock: Assert failure (TODO)
    end
Loading

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@josesimoes
Copy link
Member Author

@coderabbitai review

Copy link

coderabbitai bot commented Jun 24, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3625a85 and 522b99f.

📒 Files selected for processing (5)
  • src/CLR/Core/CLR_RT_HeapBlock.cpp (1 hunks)
  • src/CLR/Core/CLR_RT_HeapBlock_Array.cpp (1 hunks)
  • src/CLR/Core/Interpreter.cpp (1 hunks)
  • src/CLR/Diagnostics/Info.cpp (2 hunks)
  • src/CLR/Include/nanoCLR_Runtime__HeapBlock.h (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALX)
  • GitHub Check: nf-interpreter (Nightly build) (Build_STM32_targets ORGPAL_PALTHREE)
  • GitHub Check: nf-interpreter (Nightly build) (Check_Build_Options)
  • GitHub Check: nf-interpreter (Check_Build_Options)
🔇 Additional comments (8)
src/CLR/Core/Interpreter.cpp (2)

3213-3214: LGTM: Variable renaming improves code clarity.

The renaming from sig to tsInst makes the variable purpose more explicit and aligns with the naming conventions used elsewhere in the codebase for TypeSpec instances.


3219-3219: Correct implementation of generic context passing.

The addition of stack->m_call.genericType as the second parameter to SetReflection properly provides the caller's generic type context, which is essential for correct TypeSpec token resolution in generic scenarios. This change aligns perfectly with the PR objective to ensure reflection is set with the instantiated type.

src/CLR/Core/CLR_RT_HeapBlock_Array.cpp (1)

107-107: LGTM: Method call correctly updated for new signature.

The addition of caller->genericType as the second parameter provides the necessary generic type context for proper TypeSpec resolution, which aligns with the PR's objective to fix generic type handling in reflection operations.

src/CLR/Include/nanoCLR_Runtime__HeapBlock.h (1)

1350-1350: Verify all call sites have been updated for the new method signature.

The new signature with CLR_RT_TypeSpec_Instance and optional caller parameter is well-designed for improved generic type resolution. Ensure all existing call sites across the codebase have been updated to match this signature change.

#!/bin/bash
# Description: Verify all SetReflection call sites use the new signature with two parameters

# Search for SetReflection calls and check their parameter count
rg -A 5 -B 2 "\.SetReflection\(" --type cpp --type c
src/CLR/Diagnostics/Info.cpp (3)

538-538: LGTM! Consistent assembly index usage.

The change to use assemblyIndex instead of ownerAsm ensures consistency with the local context and aligns with the TypeSpec token handling improvements.


579-587: Enhanced type name formatting with proper initialization.

The changes improve type name construction by:

  1. Zero-initializing the buffer to ensure clean state
  2. Adding CLR_RT_TypeSystem::TYPENAME_FLAGS_FULL flag for complete type information
  3. Including elem.Levels parameter for proper array/pointer level handling

These enhancements align well with the PR objective of improving TypeSpec token handling for better reflection accuracy.


575-576: Verify the assembly access pattern change.

The change from tsInst.assembly to accessing via g_CLR_RT_TypeSystem.m_assemblies[genericType->Assembly() - 1] appears to improve reliability of assembly resolution. However, this introduces potential array bounds issues if genericType->Assembly() returns 0 or an invalid index.

Run the following script to verify that assembly indices are properly validated throughout the codebase:

#!/bin/bash
# Description: Search for similar assembly access patterns and bounds checking

# Search for assembly access patterns via m_assemblies array
rg -A 5 -B 5 'g_CLR_RT_TypeSystem\.m_assemblies\[.*Assembly\(\)'

# Search for bounds checking on Assembly() calls
rg -A 3 -B 3 'Assembly\(\)\s*-\s*1'

# Look for assembly index validation patterns
ast-grep --pattern 'if ($COND) {
  $$$
  Assembly() - 1
  $$$
}'
src/CLR/Core/CLR_RT_HeapBlock.cpp (1)

235-235: Consider adding parameter validation for safer generic type resolution.

The method signature looks correct for the intended TypeSpec handling improvements, but consider adding parameter validation to prevent potential issues.

Comment on lines 533 to 535
const CLR_RECORD_TYPESPEC *rec = GetTypeSpec(token);
CLR_RT_TypeSpec_Index localSpec;
localSpec.Set(assemblyIndex, token);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused local variables.

The newly introduced variables rec and localSpec are declared but never used in the visible code. This creates unnecessary memory allocation and potential confusion.

Apply this diff to remove the unused variables:

-            const CLR_RECORD_TYPESPEC *rec = GetTypeSpec(token);
-            CLR_RT_TypeSpec_Index localSpec;
-            localSpec.Set(assemblyIndex, token);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const CLR_RECORD_TYPESPEC *rec = GetTypeSpec(token);
CLR_RT_TypeSpec_Index localSpec;
localSpec.Set(assemblyIndex, token);
🤖 Prompt for AI Agents
In src/CLR/Diagnostics/Info.cpp around lines 533 to 535, the variables 'rec' and
'localSpec' are declared but never used, leading to unnecessary memory usage and
confusion. Remove the declarations and any related assignments of these two
variables to clean up the code.

Comment on lines 278 to 282
else
{
// TODO
_ASSERTE(false);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Implement handling for non-generic parameter types.

The TODO section for non-generic parameter types with _ASSERTE(false) indicates incomplete implementation. This will fail for any non-generic TypeSpec.

Based on the previous implementation that used CLR_RT_TypeDescriptor, consider implementing:

-    else
-    {
-        // TODO
-        _ASSERTE(false);
-    }
+    else
+    {
+        // Handle non-generic types using TypeDescriptor approach
+        CLR_RT_TypeDescriptor desc;
+        if (SUCCEEDED(desc.InitializeFromTypeSpec(tsInst)))
+        {
+            m_data.reflection.data.type = desc.m_handlerCls;
+            m_data.reflection.levels = elem.Levels;
+        }
+        else
+        {
+            NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
+        }
+    }

Do you want me to help complete the implementation for non-generic types based on the previous TypeDescriptor approach?

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
else
{
// TODO
_ASSERTE(false);
}
else
{
// Handle non-generic types using TypeDescriptor approach
CLR_RT_TypeDescriptor desc;
if (SUCCEEDED(desc.InitializeFromTypeSpec(tsInst)))
{
m_data.reflection.data.type = desc.m_handlerCls;
m_data.reflection.levels = elem.Levels;
}
else
{
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
}
}
🤖 Prompt for AI Agents
In src/CLR/Core/CLR_RT_HeapBlock.cpp around lines 278 to 282, the else block
handling non-generic parameter types is incomplete and currently asserts false,
which will cause failures. Replace the _ASSERTE(false) with proper handling
logic for non-generic TypeSpec parameters by implementing the approach used
previously with CLR_RT_TypeDescriptor. This involves creating a TypeDescriptor
instance for the parameter and processing it accordingly to support non-generic
types fully.

Comment on lines +272 to +276
else
{
// TODO
_ASSERTE(false);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove TODO section with always-failing assertion.

The TODO comment with _ASSERTE(false) will always trigger in debug builds when a caller is not provided for generic parameters, making this code path unusable.

-        else
-        {
-            // TODO
-            _ASSERTE(false);
-        }
+        else
+        {
+            // No caller provided for generic parameter resolution
+            NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
else
{
// TODO
_ASSERTE(false);
}
else
{
// No caller provided for generic parameter resolution
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
}
🤖 Prompt for AI Agents
In src/CLR/Core/CLR_RT_HeapBlock.cpp around lines 272 to 276, remove the TODO
comment and the _ASSERTE(false) statement that always triggers in debug builds.
Replace this section with proper handling or a more appropriate fallback to
avoid unusable code paths when a caller is not provided for generic parameters.

Comment on lines +266 to +270
if (ok)
{
m_data.reflection.data.type = tdArg;
m_data.reflection.levels = elem.Levels;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle failed generic parameter resolution properly.

When FindGenericParamAtTypeSpec returns false (ok == false), the reflection data is left uninitialized, potentially leaving the heap block in an inconsistent state.

         if (ok)
         {
             m_data.reflection.data.type = tdArg;
             m_data.reflection.levels = elem.Levels;
         }
+        else
+        {
+            NANOCLR_SET_AND_LEAVE(CLR_E_TYPE_UNAVAILABLE);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (ok)
{
m_data.reflection.data.type = tdArg;
m_data.reflection.levels = elem.Levels;
}
if (ok)
{
m_data.reflection.data.type = tdArg;
m_data.reflection.levels = elem.Levels;
}
else
{
NANOCLR_SET_AND_LEAVE(CLR_E_TYPE_UNAVAILABLE);
}
🤖 Prompt for AI Agents
In src/CLR/Core/CLR_RT_HeapBlock.cpp around lines 266 to 270, the code does not
handle the case when FindGenericParamAtTypeSpec returns false, leaving
reflection data uninitialized. Add proper handling for the failure case by
initializing or resetting the reflection data fields to a safe default state to
avoid inconsistent heap block state.

Comment on lines +264 to +265
bool ok = g_CLR_RT_TypeSystem.m_assemblies[caller->Assembly() - 1]
->FindGenericParamAtTypeSpec(caller->TypeSpec(), gpIndex, tdArg, dtArg);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add bounds checking to prevent array access violation.

The code accesses g_CLR_RT_TypeSystem.m_assemblies[caller->Assembly() - 1] without bounds checking. If Assembly() returns 0, this will cause an underflow and potential memory corruption.

+        if (caller->Assembly() == 0 || caller->Assembly() > g_CLR_RT_TypeSystem.m_assemblies.size())
+        {
+            NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
+        }
         bool ok = g_CLR_RT_TypeSystem.m_assemblies[caller->Assembly() - 1]
                       ->FindGenericParamAtTypeSpec(caller->TypeSpec(), gpIndex, tdArg, dtArg);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool ok = g_CLR_RT_TypeSystem.m_assemblies[caller->Assembly() - 1]
->FindGenericParamAtTypeSpec(caller->TypeSpec(), gpIndex, tdArg, dtArg);
if (caller->Assembly() == 0 || caller->Assembly() > g_CLR_RT_TypeSystem.m_assemblies.size())
{
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
}
bool ok = g_CLR_RT_TypeSystem.m_assemblies[caller->Assembly() - 1]
->FindGenericParamAtTypeSpec(caller->TypeSpec(), gpIndex, tdArg, dtArg);
🤖 Prompt for AI Agents
In src/CLR/Core/CLR_RT_HeapBlock.cpp around lines 264 to 265, add bounds
checking before accessing g_CLR_RT_TypeSystem.m_assemblies with index
caller->Assembly() - 1. Verify that caller->Assembly() is greater than 0 and
less than or equal to the size of m_assemblies to prevent underflow and
out-of-bounds access. Only perform the array access if these conditions are met;
otherwise, handle the error or return safely.

- Parsing a typespec when dumping an ldtoken now outputs correct type.
- Parsing a typespec when executing ldtoken IL now sets reflection with instanciated type.
- Add parameter with caller to SetReflection from TypeSpec.
- Fix calls.
@josesimoes josesimoes force-pushed the fix-ldtoken-typespec branch from 522b99f to a26cd9d Compare June 24, 2025 19:12
@josesimoes josesimoes merged commit 38faac2 into nanoframework:develop Jun 24, 2025
24 checks passed
@josesimoes josesimoes deleted the fix-ldtoken-typespec branch June 24, 2025 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Interpreter Everything related with the interpreter, execution engine and such Type: bug Type: enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants