Description
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