Skip to content

Conversation

@josesimoes
Copy link
Member

@josesimoes josesimoes commented Sep 12, 2025

Description

  • Signature parser Advance() now resets generic instance flag on parsing the instance.
  • Token resolution for TypeSpec now takes caller parameter.
  • TypeSpec Instance now caches element TypeDef on token resolution (when parsing VAR).
  • TypeSpec now stores level to deal with arrays from TypeSpecs.
  • ClearInstance() now clears all elements.
  • ldtoken handler now properly parses TypeSpec token by calling the appropriate reflection and returning the correct reflection for the closed type instance.
  • Work in HeapBlock array
    • When creating instance now uses proper reflection data with cached element type.
    • Rename local var for clarity.
    • Revert fix added before to tackle creation of jagged arrays from TypeSpec.
  • Token resolution now stores cached type for non generic instances.

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 runtime support for array types and generics resolved from metadata tokens.
    • Context-aware type resolution ensures correct handling of closed generic types during execution.
  • Bug Fixes

    • More reliable reflection when creating arrays and resolving type information.
    • Correct handling of array and nested type specifications, reducing runtime errors.
    • Enhanced error handling to prevent failures with unresolved or invalid generic parameters.

- Token resolution for TypeSpec now takes caller parameter.
- TypeSpec Instance now caches element TypeDef on token resolution (when parsing VAR).
- TypeSpec now stores level to deal with arrays from TypeSpecs.
- ClearInstance() now clears all elements.
- Calls appropriate reflection and returning the correct reflection for the closed type instance.
- When creating instance now uses proper reflection data with cached element type.
- Rename local var for clarity.
- Revert fix added before to tackle creation of jagged arrays from TypeSpec.
@josesimoes josesimoes added the Area: Common libs Everything related with common libraries label Sep 12, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 12, 2025

Walkthrough

The change set updates TypeSpec resolution to be context-aware (caller-based), adds array TypeSpec handling in the interpreter, modifies array instance creation to use synthesized reflections from TypeSpec, and expands the type system with new fields and updated ResolveToken signatures. Public headers are updated accordingly.

Changes

Cohort / File(s) Summary of changes
Type system API and context-aware resolution
src/CLR/Core/TypeSystem.cpp, src/CLR/Include/nanoCLR_Runtime.h
Added fields levels and cachedElementType to CLR_RT_TypeSpec_Instance. ResolveToken for TypeSpec and TypeDef now accept an optional caller context. Implemented caller-aware resolution for VAR/MVAR and TypeSpec (including arrays), stricter initialization/clearing, parser flag reset, and error handling.
Interpreter TypeSpec handling
src/CLR/Core/Interpreter.cpp
CEE_LDTOKEN now resolves TypeSpec using the caller’s generic context. Added array TypeSpec support by constructing a REFLECTION_TYPE with levels and element type. Improved non-array TypeSpec resolution using generic type or cached element type.
Array creation path
src/CLR/Core/CLR_RT_HeapBlock_Array.cpp
Removed legacy TypeSpec/type descriptor resolution path. For TypeSpec tokens, create a synthetic REFLECTION_TYPE using tsInst.levels and cachedElementType, then SetReflection. Early error for non-REFLECTION_TYPE; simplified single-level handling using reflex.data.type.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant IL as IL Interpreter
  participant TS as CLR_RT_TypeSpec_Instance
  participant TD as CLR_RT_TypeDef_Instance
  participant MD as Caller Method (context)

  rect rgba(230,240,255,0.6)
    note over IL: CEE_LDTOKEN on TypeSpec
    IL->>TS: ResolveToken(tsToken, assm, caller=MD)
    alt VAR/MVAR in TypeSpec
      TS->>MD: Query generic bindings
      TS->>TD: Map generic param to concrete type
      TD-->>TS: Resolved typeDef
    else Non-generic or concrete TypeSpec
      TS-->>IL: levels, cachedElementType / genericTypeDef
    end
  end

  alt Array TypeSpec (levels > 0)
    IL->>IL: Build REFLECTION_TYPE { levels, element = (genericTypeDef | cachedElementType) }
    IL-->>IL: Push reflection to eval stack
  else Non-array TypeSpec
    IL->>IL: Determine reflection from concrete/generic type
    IL-->>IL: Push reflection to eval stack
  end
Loading
sequenceDiagram
  autonumber
  participant VM as Runtime
  participant TS as CLR_RT_TypeSpec_Instance
  participant AR as CLR_RT_HeapBlock_Array

  rect rgba(240,255,240,0.6)
    note over VM: Array.CreateInstance with TypeSpec token
    VM->>TS: ResolveToken(tsToken, assm, caller)
    TS-->>VM: levels, cachedElementType
    VM->>AR: CreateInstance(reference, length, assm, tk, caller)
    AR->>AR: Synthesize REFLECTION_TYPE { kind=TYPE, levels, data.type=cachedElementType }
    AR->>AR: SetReflection(reflex)
    AR-->>VM: Array instance created
  end

  rect rgba(255,245,230,0.6)
    note over AR: Non-REFLECTION_TYPE rejected early
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks (1 passed, 1 warning, 1 inconclusive)

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The current title "More generic fixes" is vague and does not convey the primary changes in this PR, which center on TypeSpec/TypeDef resolution (making ResolveToken caller-aware), caching element types, and improved array handling; because it is generic and non-descriptive, the check is inconclusive. Please rename the PR to a concise, descriptive title such as "TypeSpec: make ResolveToken caller-aware, cache element types, and add array support" or "TypeSystem: caller-aware TypeSpec resolution and element-type caching" so reviewers can immediately understand the primary intent.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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.

@josesimoes josesimoes changed the base branch from main to develop September 12, 2025 15:50
nfbot and others added 2 commits September 12, 2025 16:53
Automated fixes for code style.
@josesimoes
Copy link
Member Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 12, 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
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

🧹 Nitpick comments (3)
src/CLR/Include/nanoCLR_Runtime.h (1)

2089-2094: Initialize and document new fields (levels, cachedElementType)

Confirm ClearInstance() and all initializers zero these new members; add a brief comment describing their semantics (array-rank; cached element TypeDef for VAR/MVAR or non-generic cases).

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

3310-3313: Fix typo in comment

Minor nit in the added comment: “caller’sc”.

Apply:

-// this has to provide the closed instance of the type in the context of the caller'sc
+// this has to provide the closed instance of the type in the context of the caller's
src/CLR/Core/CLR_RT_HeapBlock_Array.cpp (1)

120-123: Array-rank increment: sanity check (nit)

ref.ReflectionData().levels++ can overflow CLR_UINT16 (ReflectionDef uses 16 bits). Unlikely but consider guarding or asserting in debug builds.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89cfb9f and a2d661a.

📒 Files selected for processing (4)
  • src/CLR/Core/CLR_RT_HeapBlock_Array.cpp (2 hunks)
  • src/CLR/Core/Interpreter.cpp (1 hunks)
  • src/CLR/Core/TypeSystem.cpp (6 hunks)
  • src/CLR/Include/nanoCLR_Runtime.h (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-14T17:33:51.546Z
Learnt from: josesimoes
PR: nanoframework/nf-interpreter#3172
File: src/CLR/Core/TypeSystem.cpp:4556-4589
Timestamp: 2025-05-14T17:33:51.546Z
Learning: When parsing TypeSpec signatures in nanoFramework, the first Advance() call consumes the VAR/MVAR token, followed by additional Advance() calls to walk to the specific generic parameter position.

Applied to files:

  • src/CLR/Core/TypeSystem.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: nf-interpreter (Build_nanoCLR_CLI)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_ETHERNET_KIT_1.2)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_S3_ALL)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_H2_THREAD)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_C6_THREAD)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_C3)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_BLE_REV0)
  • GitHub Check: nf-interpreter (Build_WIN32_nanoCLR)
  • GitHub Check: nf-interpreter (Build_ESP32_targets ESP32_PSRAM_REV0)
  • GitHub Check: nf-interpreter (Build_STM32_targets ST_STM32F769I_DISCOVERY)
  • GitHub Check: nf-interpreter (Build_NXP_targets NXP_MIMXRT1060_EVK)
  • GitHub Check: nf-interpreter (Build_Azure_RTOS_targets SL_STK3701A)
  • GitHub Check: nf-interpreter (Build_TI_SimpleLink_targets TI_CC1352R1_LAUNCHXL_915)
  • GitHub Check: nf-interpreter (Build_STM32_targets ST_STM32F429I_DISCOVERY)
  • 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 (Check_Code_Style)
  • GitHub Check: nf-interpreter (Nightly build) (Check_Build_Options)
  • GitHub Check: nf-interpreter (Check_Build_Options)
🔇 Additional comments (12)
src/CLR/Include/nanoCLR_Runtime.h (1)

2089-2101: Propagate the new caller argument to every CLR_RT_TypeSpec_Instance::ResolveToken call site.
The optional caller must be forwarded from callers (especially array/TypeSpec resolution paths) to avoid resolving open generics in the wrong context. Automated scan returned no ResolveToken usages—verify manually.

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

3310-3365: Context-aware TypeSpec resolution for ldtoken: LGTM

Passing &stack->m_call and synthesizing array reflections via levels/element TypeDef is the right fix for closed-type instances and arrays.

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

27-35: Array CreateInstance(reflection) strictness: LGTM

Early exit on non-REFLECTION_TYPE and direct use of reflex.data.type for rank-1 is sound given the new upstream synthesis.

src/CLR/Core/TypeSystem.cpp (9)

619-621: Reset generic instance flag correctly after parsing the instance.

Good fix. This ensures the IsGenericInst flag is properly reset after processing a generic instance, preventing incorrect state from persisting to subsequent parsing operations.


714-721: Add error handling for signature parsing in TypeSpec initialization.

The addition of error handling for parser.Advance() is a good defensive programming practice. This ensures that malformed TypeSpec signatures are caught early and the instance is properly cleared on failure.


722-722: Store levels from parsed element for array handling.

Caching the levels value from the parsed element is essential for proper array TypeSpec handling, especially for jagged arrays originating from TypeSpecs.


735-735: Use ClearInstance() for consistent cleanup.

Good consistency improvement. Using ClearInstance() instead of direct field nulling ensures all fields are properly reset, reducing the chance of leaving the instance in an inconsistent state.


747-750: Comprehensive cleanup in ClearInstance().

The additions to ClearInstance() ensure that all new fields (levels, genericTypeDef, and resetting data) are properly cleared. This prevents stale data from persisting across instance reuses.


752-756: Add caller context to ResolveToken for generic resolution.

The addition of the caller parameter to ResolveToken enables context-aware type resolution, which is crucial for properly resolving type-generic slots (!T) and method-generic slots (!!T) in generic contexts.


775-776: Cache levels for array handling in TypeSpec resolution.

Good addition. Storing the levels value during token resolution ensures array dimension information is preserved for later use.


784-821: Implement VAR handling for type-generic parameters.

The implementation correctly resolves type-generic parameters (!T) against the caller's closed generic type. The error handling for null caller or genericType is appropriate, ensuring the function fails gracefully when the required context is missing.

The resolution logic:

  1. Extracts the generic parameter position
  2. Uses the caller's bound genericType to find the actual type
  3. Updates assembly and target references
  4. Stores the resolved type in cachedElementType

This is a critical fix for proper generic type instantiation.


815-821: Cache element type for non-generic instances.

Good addition. Storing the cachedElementType for non-generic instances ensures that the element type information is available when needed, particularly for array creation from TypeSpecs.

@josesimoes josesimoes merged commit d3f31e2 into nanoframework:develop Sep 12, 2025
24 checks passed
@josesimoes josesimoes deleted the more-generic-fixes branch September 12, 2025 16:34
@josesimoes josesimoes changed the title More generic fixes More fixes with generics Sep 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Common libs Everything related with common libraries Type: bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants