Skip to content

Compiling against methods that accept params span with only System.Runtime reference produces compiler error #102513

Closed
@ericstj

Description

@ericstj

Description

We have API in System.Runtime that accepts params ReadonlySpan. Normally we'd be able to consume any API in System.Runtime with just a reference to System.Runtime - but calling these new APIs demands System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpan

I wonder if we should push this type down, perhaps others in System.Memory as well. It's implementation already lives in System.Private.CoreLib

Reproduction Steps

Here's a repro that demonstrates a customer scenario where they do runtime compilation and specify System.Runtime only as a reference. This isn't too farfetched since we recommend that folks use reference assemblies.

compileSR.zip -> derived from https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/may/net-core-cross-platform-code-generation-with-roslyn-and-net-core#executing-code-the-emit-apis sample

using System.Reflection;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;

const string code = """
        public static class C
        {
            public static string M() => string.Concat("Hello", " ", "World", "!", "!", "!");
        }
        """;
var tree = SyntaxFactory.ParseSyntaxTree(code, new CSharpParseOptions(LanguageVersion.Preview));
string fileName="lib.dll";
// add reference to only System.Runtime
var systemRuntimeRefLocation=Path.Combine(AppContext.BaseDirectory, "refs", "System.Runtime.dll");
var systemRuntimeReference = MetadataReference.CreateFromFile(systemRuntimeRefLocation);
var compilation = CSharpCompilation.Create(fileName)
    .WithOptions(
        new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
    .AddReferences(systemRuntimeReference)
    .AddSyntaxTrees(tree);
string path = Path.Combine(Directory.GetCurrentDirectory(), fileName);

EmitResult compilationResult = compilation.Emit(path);
if(compilationResult.Success)
{
    // Load the assembly
    Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
    object? result = asm!.GetType("C")!.GetMethod("M")!.Invoke(null, []);
    Console.WriteLine(result);
}
else
{
    foreach (Diagnostic codeIssue in compilationResult.Diagnostics)
    {
        string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()}, Location: {codeIssue.Location.GetLineSpan()}, Severity: {codeIssue.Severity}";
        Console.WriteLine(issue);
    }
}

Expected behavior

Comple successful and output "Hello World!!!"

Actual behavior

ID: CS0656, Message: Missing compiler required member 'System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpan', Location: : (0,0)-(0,0), Severity: Error

Regression?

Yes, the addition of the params ReadOnlySpan overloads introduced this break.

Known Workarounds

Add a reference to System.Memory

Configuration

No response

Other information

See dotnet/sdk#41014 for some background. CC @333fred @jaredpar @jozkee

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions