Skip to content

Better support for unmanaged-like types #76928

Open
@vmilea

Description

@vmilea

Background

Recent efforts have improved the predictability of layout in managed memory (for example, non-blittable bool / char fields no longer break sequential layout on the managed side). This enables high-performance serialization and interop without runtime marshalling or explicit layout attributes.

Motivation

I'm building an API that that takes blittable types:

void Blit(ReadOnlySpan<T> items) { ... }

"Blittable" in this case means unmanaged or nullable unmanaged. Yes, Nullable<T> where T : unmanaged is in fact blittable, let's move on. :)

Because Nullable<T> doesn't satisfy the struct / unmanaged constraints, you end up defining multiple overloads:

void Blit<T>(in T value) where T : unmanaged { ... }
void Blit<T>(in T? value) where T : unmanaged { ... }

This becomes exponentially worse the more blittable parameters there are:

void Blit<T1, T2>(in T1 a, in T2 b) where T1 : unmanaged where T2 : unmanaged { ... }
void Blit<T1, T2>(in T1 a, in T2? b) where T1 : unmanaged where T2 : unmanaged { ... }
void Blit<T1, T2>(in T1? a, in T2 b) where T1 : unmanaged where T2 : unmanaged { ... }
void Blit<T1, T2>(in T1? a, in T2? b) where T1 : unmanaged where T2 : unmanaged { ... }

So I decided to leave T unconstrained and instead throw an exception when the RuntimeHelpers.IsReferenceOrContainsReferences<T>() intrinsic returns false. This approach detects issues at runtime with zero overhead, but I'd like to add an analyzer error in case of misuse.

void Blit<[Blittable] T>(in T value) { ... }
...

Blit("oops"); // Error: Type 'string' is not Blittable

Proposed API

A couple of additions to the Roslyn API would help:

  • ITypeSymbol.IsReferenceOrContainsReferences: Equivalent to RuntimeHelpers.IsReferenceOrContainsReferences. Can already be done by checking all fields in a struct recursively, but should be faster through a dedicated API.

  • INamedTypeSymbol.LayoutKind: So the analyzer can warn against auto layout, which is currently tricky to infer (e.g. can't assume sequential layout for a struct lacking StructLayoutAttribute because it might be a forwarded type like ValueTuple and it has a TypeForwardedFromAttribute instead of the original attributes).

namespace Microsoft.CodeAnalysis
{
    public interface INamedTypeSymbol : ITypeSymbol
    {
+       System.Runtime.InteropServices.LayoutKind LayoutKind { get; }
    }
}

Risks

Can't see any.

Metadata

Metadata

Assignees

Labels

Area-CompilersConcept-APIThis issue involves adding, removing, clarification, or modification of an API.Feature RequestNeeds API ReviewNeeds to be reviewed by the API review councilapi-approvedAPI was approved in API review, it can be implemented

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions