Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 20, 2025

Array.Initialize() silently fails in NativeAOT when the element type's default constructor lacks reflection metadata. The runtime API returns IntPtr.Zero when the constructor isn't preserved, causing Initialize to skip all elements.

Changes

  • UsageBasedMetadataManager.cs: Added dependency tracking for array element type default constructors in GetMetadataDependenciesDueToReflectability. When an array type becomes reflectable, preserve the element type's default constructor if it's a value type.

  • Test: Added TestArrayInitialize to verify Array.Initialize invokes constructors correctly. Uses a struct with parameterless constructor that increments a static counter to validate execution.

// Without this fix, Initialize() does nothing and counter stays 0
public struct ValueTypeWithConstructor
{
    public ValueTypeWithConstructor() { s_constructorCallCount++; }
}

var array = new ValueTypeWithConstructor[3];
array.Initialize();  // Now correctly calls constructor 3 times

The fix follows the same pattern as existing delegate Invoke method preservation (lines 299-312).

Original prompt

Update UsageBasedMetadataManager.cs so that GetMetadataDependenciesDueToReflectability, when invoked for an array type, checks if the element type is a value type and if GetDefaultConstructor on the element type returns non-null. If so, add a dependency on ReflectedMethod for the canonical form of the default constructor. This ensures that Array.Initialize works reliably for value types with a public parameterless constructor in NativeAOT scenarios where reflection metadata may not otherwise be generated.

Include a test under src/tests/nativeaot/SmokeTests/Reflection that:

  • Defines a value type with a public parameterless constructor.
  • Allocates an array of that value type.
  • Calls Initialize() on the array and verifies, via reflection or side effect, that the constructor ran on every element.
  • The test should fail if the default constructor is not reflectable.

Motivation: In NativeAOT, the default constructor may not be preserved for reflection unless explicitly marked as a dependency. This causes Array.Initialize to silently do nothing if the metadata is missing, violating developer expectations.

This pull request was created as a result of the following prompt from Copilot chat.

Update UsageBasedMetadataManager.cs so that GetMetadataDependenciesDueToReflectability, when invoked for an array type, checks if the element type is a value type and if GetDefaultConstructor on the element type returns non-null. If so, add a dependency on ReflectedMethod for the canonical form of the default constructor. This ensures that Array.Initialize works reliably for value types with a public parameterless constructor in NativeAOT scenarios where reflection metadata may not otherwise be generated.

Include a test under src/tests/nativeaot/SmokeTests/Reflection that:

  • Defines a value type with a public parameterless constructor.
  • Allocates an array of that value type.
  • Calls Initialize() on the array and verifies, via reflection or side effect, that the constructor ran on every element.
  • The test should fail if the default constructor is not reflectable.

Motivation: In NativeAOT, the default constructor may not be preserved for reflection unless explicitly marked as a dependency. This causes Array.Initialize to silently do nothing if the metadata is missing, violating developer expectations.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

- Modified UsageBasedMetadataManager.cs to add metadata dependency for array element type default constructors
- Added TestArrayInitialize test to verify Array.Initialize works with value types having parameterless constructors

Co-authored-by: MichalStrehovsky <[email protected]>
Copilot AI changed the title [WIP] Update GetMetadataDependenciesDueToReflectability for array types Fix Array.Initialize for value types with default constructors in NativeAOT Nov 20, 2025
Copilot finished work on behalf of MichalStrehovsky November 20, 2025 08:02
@MichalStrehovsky MichalStrehovsky marked this pull request as ready for review November 20, 2025 17:28
Copilot AI review requested due to automatic review settings November 20, 2025 17:28
Copilot finished reviewing on behalf of MichalStrehovsky November 20, 2025 17:32
@MichalStrehovsky
Copy link
Member

Cc @dotnet/ilc-contrib for review.

I'm running into this in #121697

This is a simplified change that simply adds a reflectable default constructor whenever we see an array of valuetypes with a default constructor was allocated.

In the limit what we could do instead is add this to dataflow analysis and if the array type on which Array.Initialize was called was known, only enable that specific array type, or enable all arrays if the type wasn't known. It is probably not worth the hassle. rt-sz reports pretty much no regression: MichalStrehovsky/rt-sz#198

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes a bug in NativeAOT where Array.Initialize() would silently fail to invoke default constructors on value types when the constructor's reflection metadata wasn't preserved. The runtime's TryGetDefaultConstructorForType API returns IntPtr.Zero when a constructor lacks metadata, causing Initialize() to skip all elements.

Key Changes:

  • Added dependency tracking in the compiler to preserve default constructors for array element types that are value types
  • Included comprehensive test coverage to validate that Array.Initialize() correctly invokes constructors

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
UsageBasedMetadataManager.cs Added logic to preserve default constructor metadata for value type array elements when array type becomes reflectable
Reflection.cs Added test that verifies Array.Initialize() correctly invokes constructors on value type elements using a static counter

@MichalStrehovsky MichalStrehovsky enabled auto-merge (squash) November 20, 2025 21:15
@MichalStrehovsky MichalStrehovsky merged commit 8498fc7 into main Nov 21, 2025
100 of 102 checks passed
@MichalStrehovsky MichalStrehovsky deleted the copilot/update-metadata-dependencies-reflectability branch November 21, 2025 07:55
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.

3 participants