Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mitigate first-class Span breaks #108789

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -352,30 +352,30 @@
<Uri>https://github.com/dotnet/runtime-assets</Uri>
<Sha>d953443109b1efa5a324290b65534b89017cb744</Sha>
</Dependency>
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.12.0-3.24476.1">
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.13.0-1.24510.9">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>1ed3c1b184f9da5b9f71097672b63edb00858fad</Sha>
<Sha>c9dd07d64fc446208f36e55bdc305478e915ca3f</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis" Version="4.12.0-3.24476.1">
<Dependency Name="Microsoft.CodeAnalysis" Version="4.13.0-1.24510.9">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>1ed3c1b184f9da5b9f71097672b63edb00858fad</Sha>
<Sha>c9dd07d64fc446208f36e55bdc305478e915ca3f</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.CSharp" Version="4.12.0-3.24476.1">
<Dependency Name="Microsoft.CodeAnalysis.CSharp" Version="4.13.0-1.24510.9">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>1ed3c1b184f9da5b9f71097672b63edb00858fad</Sha>
<Sha>c9dd07d64fc446208f36e55bdc305478e915ca3f</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0-beta1.24467.1">
<Dependency Name="Microsoft.CodeAnalysis.Analyzers" Version="3.12.0-beta1.24508.1">
<Uri>https://github.com/dotnet/roslyn-analyzers</Uri>
<Sha>f4c8475010cbc3d5956c99c1f2c2d49c03c5871b</Sha>
<Sha>8c173ced8bb1545be6eb70a1a8a5dcff0a557457</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.0-preview.24467.1">
<Dependency Name="Microsoft.CodeAnalysis.NetAnalyzers" Version="10.0.0-preview.24508.1">
<Uri>https://github.com/dotnet/roslyn-analyzers</Uri>
<Sha>f4c8475010cbc3d5956c99c1f2c2d49c03c5871b</Sha>
<Sha>8c173ced8bb1545be6eb70a1a8a5dcff0a557457</Sha>
</Dependency>
<!-- Intermediate is necessary for source build. -->
<Dependency Name="Microsoft.SourceBuild.Intermediate.roslyn" Version="4.12.0-3.24476.1">
<Dependency Name="Microsoft.SourceBuild.Intermediate.roslyn" Version="4.13.0-1.24510.9">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>1ed3c1b184f9da5b9f71097672b63edb00858fad</Sha>
<Sha>c9dd07d64fc446208f36e55bdc305478e915ca3f</Sha>
<SourceBuild RepoName="roslyn" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.DotNet.ApiCompat.Task" Version="10.0.100-alpha.1.24480.5">
Expand Down
10 changes: 5 additions & 5 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@
</ItemGroup>
<PropertyGroup>
<!-- dotnet/roslyn-analyzers dependencies -->
<MicrosoftCodeAnalysisAnalyzersVersion>3.11.0-beta1.24467.1</MicrosoftCodeAnalysisAnalyzersVersion>
<MicrosoftCodeAnalysisNetAnalyzersVersion>10.0.0-preview.24467.1</MicrosoftCodeAnalysisNetAnalyzersVersion>
<MicrosoftCodeAnalysisAnalyzersVersion>3.12.0-beta1.24508.1</MicrosoftCodeAnalysisAnalyzersVersion>
<MicrosoftCodeAnalysisNetAnalyzersVersion>10.0.0-preview.24508.1</MicrosoftCodeAnalysisNetAnalyzersVersion>
<!-- dotnet/roslyn dependencies -->
<!--
These versions should not be used by any project that contributes to the design-time experience in VS, such as an analyzer, code-fix, or generator assembly.
Any tools that contribute to the design-time experience should use the MicrosoftCodeAnalysisVersion_LatestVS property above to ensure
they do not break the local dev experience.
-->
<MicrosoftCodeAnalysisCSharpVersion>4.12.0-3.24476.1</MicrosoftCodeAnalysisCSharpVersion>
<MicrosoftCodeAnalysisVersion>4.12.0-3.24476.1</MicrosoftCodeAnalysisVersion>
<MicrosoftNetCompilersToolsetVersion>4.12.0-3.24476.1</MicrosoftNetCompilersToolsetVersion>
<MicrosoftCodeAnalysisCSharpVersion>4.13.0-1.24510.9</MicrosoftCodeAnalysisCSharpVersion>
<MicrosoftCodeAnalysisVersion>4.13.0-1.24510.9</MicrosoftCodeAnalysisVersion>
<MicrosoftNetCompilersToolsetVersion>4.13.0-1.24510.9</MicrosoftNetCompilersToolsetVersion>
</PropertyGroup>
<!--
For source generator support we need to target multiple versions of Roslyn in order to be able to run on older versions of Roslyn.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
<LangVersion>latest</LangVersion>
Copy link
Member Author

Choose a reason for hiding this comment

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

This project was building against net8.0, net9.0 with C# 14 (preview). That means it gets the first-class Span feature but not the Enumerable.Reverse(this T[]) API. I changed it to build with langversion=latest instead of preview. I could alternatively change the specific Reverse() usage, but in general building older TFMs with newer langversions is unsupported, so this seemed better.

Copy link
Member

Choose a reason for hiding this comment

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

What will that mean when C# 14 is latest? We'll still be building this against net8.0 at that time.

Copy link
Member Author

@jjonescz jjonescz Oct 11, 2024

Choose a reason for hiding this comment

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

But when you are targeting net8.0, then you are getting LangVersion=13 as latest, I think. But yeah, there was just one break here I think, so I could just explicitly use Enumerable.Range as well.

Copy link
Member

Choose a reason for hiding this comment

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

That's not the case. latest does not take TFM into account, e.g. if I create a .NET Framework 4.8 app, it defaults to using C# 7.3, but if I change LangVer to latest, I get the most recent version my compiler supports.

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense, I removed this.

<Nullable>disable</Nullable>
<NoWarn>$(NoWarn);nullable</NoWarn>
<EnableDefaultItems>true</EnableDefaultItems>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ public void PeekRef_Empty()
protected override IEnumerable<T> GetEnumerableOf<T>(params T[] contents)
{
ImmutableStack<T> stack = ImmutableStack<T>.Empty;
foreach (T value in contents.Reverse())
foreach (T value in Enumerable.Reverse(contents))
Copy link
Member Author

Choose a reason for hiding this comment

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

This mitigation is only needed in runtime, user code shouldn't break (unless they write code into System namespace).

The break is because MemoryExtensions.Reverse<T>(this Span<T>) is now applicable for array.Reverse(). Because Span is better than IEnumerable by overload resolution rules, code like array.Reverse() would break when going from C# 13 to C# 14. So we added Enumerable.Reverse<T>(this T[]) overload (#107723) which is preferred in normal scenarios for arrays. But it actually doesn't have an effect here since we are in the System namespace, so System.MemoryExtensions is found and then the search stops and doesn't reach System.Linq.Enumerable.

Copy link
Member

Choose a reason for hiding this comment

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

This mitigation is only needed in runtime, user code shouldn't break (unless they write code into System namespace).

BTW this is not using System namespace https://github.com/dotnet/aspnetcore/blob/c9df8c1550a941f104db3b442a13587a2fcb901c/src/DataProtection/DataProtection/src/Internal/ContainerUtils.cs#L106 and yet we are getting /vmr/src/aspnetcore/src/DataProtection/DataProtection/src/Internal/ContainerUtils.cs(106,31): error CS0023: Operator '.' cannot be applied to operand of type 'void' [/vmr/src/aspnetcore/src/DataProtection/DataProtection/src/Microsoft.AspNetCore.DataProtection.csproj::TargetFramework=netstandard2.0]

Copy link
Member

@stephentoub stephentoub Nov 3, 2024

Choose a reason for hiding this comment

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

It doesn't have the new Enumerable.Reverse(T[]) overload.

{
stack = stack.Push(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public static void Set_CustomComparerTest()

int visited = s_dictionaryData.Length;

Assert.All(s_dictionaryData.Reverse(), element =>
Assert.All(Enumerable.Reverse(s_dictionaryData), element =>
Copy link
Member

Choose a reason for hiding this comment

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

Why does this one need to change? We're only building here for netcoreappcurrent, which should be able to see the array-based overload, right?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, are these all in the same boat as your comment on the immutable tests, that they're not seeing the new Enumerable overload because the tests themselves are in the system namespace?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, these are all in the same boat; they are all in System namespace.

{
string newValue = "new" + element.Value;
Assert.True(ld.Contains(element.Key));
Expand All @@ -154,7 +154,7 @@ public static void Remove_CustomComparerTest()
ObservableStringComparer comparer = new ObservableStringComparer();
ListDictionary ld = Fill(new ListDictionary(comparer), s_dictionaryData);

Assert.All(s_dictionaryData.Reverse(), element =>
Assert.All(Enumerable.Reverse(s_dictionaryData), element =>
{
int originalSize = ld.Count;
Assert.True(ld.Contains(element.Key));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ public void Queue_Generic_ToArray_NonWrappedQueue(int count)
Queue<T> collection = new Queue<T>(count + 1);
AddToCollection(collection, count);
T[] elements = collection.ToArray();
elements.Reverse();
Copy link
Member

Choose a reason for hiding this comment

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

:)

Assert.True(Enumerable.SequenceEqual(elements, collection.ToArray<T>()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void Stack_Generic_Constructor_IEnumerable(EnumerableType enumerableType,
_ = numberOfMatchingElements;
IEnumerable<T> enumerable = CreateEnumerable(enumerableType, null, enumerableLength, 0, numberOfDuplicateElements);
Stack<T> stack = new Stack<T>(enumerable);
Assert.Equal(enumerable.ToArray().Reverse(), stack.ToArray());
Assert.Equal(Enumerable.Reverse(enumerable.ToArray()), stack.ToArray());
Copy link
Member

Choose a reason for hiding this comment

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

Same for many of these... I'm not clear on why changes here are necessary

Copy link
Member Author

Choose a reason for hiding this comment

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

Same reason as the other ones - the System namespace problem.

}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ private static CompositionError CreateCompositionError(CompositionErrorId id, st
private static CompositionError CreateCompositionError(params string[] messages)
{
CompositionError error = null;
foreach (string message in messages.Reverse())
foreach (string message in Enumerable.Reverse(messages))
{
CompositionException exception = null;
if (error != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ public void WriteFooterTest_LogicalOperationStack()
listener.Flush();

Assert.Contains("LogicalOperationStack=", listener.Output);
Assert.Contains(string.Join(", ", items.Reverse()), listener.Output);
Assert.Contains(string.Join(", ", Enumerable.Reverse(items)), listener.Output);
}
finally
{
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Memory/tests/Memory/CopyTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static void TryCopyToArraySegmentImplicit()
Memory<int> srcMemory = src;
bool success = srcMemory.TryCopyTo(segment);
Assert.True(success);
Assert.Equal(src, segment);
Assert.Equal(src.AsSpan(), segment);
Copy link
Member Author

Choose a reason for hiding this comment

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

There are some ambiguities in xunit that should be resolved by updating (xunit/xunit#3021) but that seemed like a complex task (to update xunit in dotnet/runtime)

}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Memory/tests/ReadOnlySpan/CopyTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static void TryCopyToArraySegmentImplicit()
ReadOnlySpan<int> srcSpan = new ReadOnlySpan<int>(src);
bool success = srcSpan.TryCopyTo(segment);
Assert.True(success);
Assert.Equal(src, segment);
Assert.Equal(src.AsSpan(), segment);
}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Memory/tests/Span/CopyTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static void TryCopyToArraySegmentImplicit()
Span<int> srcSpan = new Span<int>(src);
bool success = srcSpan.TryCopyTo(segment);
Assert.True(success);
Assert.Equal(src, segment);
Assert.Equal(src.AsSpan(), segment);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ internal static void GetStoreValuesAsStringOrStringArray(HeaderDescriptor descri
else
{
Debug.Assert(length > 1, "The header should have been removed when it became empty");
values = multiValue = new string[length];
values = (multiValue = new string[length])!;
Copy link
Member Author

Choose a reason for hiding this comment

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

Nullability changed a bit where previously user-defined conversions between Spans and arrays were involved and now the built-in implicit span conversions are used. The rules should be actually "better", for example this code was assigning string[] to Span<string?> without nullability warnings.

}

int currentIndex = 0;
Expand Down Expand Up @@ -1205,8 +1205,8 @@ internal static int GetStoreValuesIntoStringArray(HeaderDescriptor descriptor, o
}

int currentIndex = 0;
ReadStoreValues<object?>(values, info.ParsedAndInvalidValues, descriptor.Parser, ref currentIndex);
ReadStoreValues<string?>(values, info.RawValue, null, ref currentIndex);
ReadStoreValues<object?>(values!, info.ParsedAndInvalidValues, descriptor.Parser, ref currentIndex);
ReadStoreValues<string?>(values!, info.RawValue, null, ref currentIndex);
Debug.Assert(currentIndex == length);

return length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2658,7 +2658,7 @@ public static Tensor<T> PermuteDimensions<T>(this Tensor<T> tensor, params ReadO

if (dimensions.IsEmpty)
{
lengths = tensor._lengths.Reverse().ToArray();
lengths = Enumerable.Reverse(tensor._lengths).ToArray();
Copy link
Member

Choose a reason for hiding this comment

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

@michaelgsharp, subsequently we should avoid using LINQ in these cases.

Copy link
Member

Choose a reason for hiding this comment

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

This instance of LINQ usage was addressed in the changes from #109405, as it was hindering the source-build codeflow. Perhaps we should consider removing LINQ usage entirely from tensor computation (to ensure more efficient and optimized code).

Copy link
Member

Choose a reason for hiding this comment

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

permutation = Enumerable.Range(0, tensor.Rank).Reverse().ToArray();
}
else
Expand Down
40 changes: 20 additions & 20 deletions src/libraries/System.Numerics.Tensors/tests/TensorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ public static void TensorMultiplyTests()
Tensor<int> t1 = Tensor.Create(Enumerable.Range(0, 3), [3, 1]);
Tensor<int> t2 = Tensor.Multiply(t0.AsReadOnlyTensorSpan(), t1);

Assert.Equal([3,3], t2.Lengths.ToArray());
Assert.Equal([3,3], t2.Lengths);
Assert.Equal(0, t2[0, 0]);
Assert.Equal(0, t2[0, 1]);
Assert.Equal(0, t2[0, 2]);
Expand All @@ -697,7 +697,7 @@ public static void TensorMultiplyTests()

t2 = Tensor.Multiply(t1.AsReadOnlyTensorSpan(), t0);

Assert.Equal([3, 3], t2.Lengths.ToArray());
Assert.Equal([3, 3], t2.Lengths);
Assert.Equal(0, t2[0, 0]);
Assert.Equal(0, t2[0, 1]);
Assert.Equal(0, t2[0, 2]);
Expand All @@ -711,7 +711,7 @@ public static void TensorMultiplyTests()
t1 = Tensor.Create(Enumerable.Range(0, 9), [3, 3]);
t2 = Tensor.Multiply(t0.AsReadOnlyTensorSpan(), t1);

Assert.Equal([3, 3], t2.Lengths.ToArray());
Assert.Equal([3, 3], t2.Lengths);
Assert.Equal(0, t2[0, 0]);
Assert.Equal(1, t2[0, 1]);
Assert.Equal(4, t2[0, 2]);
Expand All @@ -729,7 +729,7 @@ public static void TensorBroadcastTests()
Tensor<int> t0 = Tensor.Create(Enumerable.Range(0, 3), [1, 3, 1, 1, 1]);
Tensor<int> t1 = Tensor.Broadcast<int>(t0, [1, 3, 1, 2, 1]);

Assert.Equal([1, 3, 1, 2, 1], t1.Lengths.ToArray());
Assert.Equal([1, 3, 1, 2, 1], t1.Lengths);

Assert.Equal(0, t1[0, 0, 0, 0, 0]);
Assert.Equal(0, t1[0, 0, 0, 1, 0]);
Expand All @@ -739,7 +739,7 @@ public static void TensorBroadcastTests()
Assert.Equal(2, t1[0, 2, 0, 1, 0]);

t1 = Tensor.Broadcast<int>(t0, [1, 3, 2, 1, 1]);
Assert.Equal([1, 3, 2, 1, 1], t1.Lengths.ToArray());
Assert.Equal([1, 3, 2, 1, 1], t1.Lengths);

Assert.Equal(0, t1[0, 0, 0, 0, 0]);
Assert.Equal(0, t1[0, 0, 1, 0, 0]);
Expand All @@ -751,7 +751,7 @@ public static void TensorBroadcastTests()
t0 = Tensor.Create(Enumerable.Range(0, 3), [1, 3]);
t1 = Tensor.Create(Enumerable.Range(0, 3), [3, 1]);
var t2 = Tensor.Broadcast<int>(t0, [3, 3]);
Assert.Equal([3, 3], t2.Lengths.ToArray());
Assert.Equal([3, 3], t2.Lengths);

Assert.Equal(0, t2[0, 0]);
Assert.Equal(1, t2[0, 1]);
Expand All @@ -765,7 +765,7 @@ public static void TensorBroadcastTests()

t1 = Tensor.Create(Enumerable.Range(0, 3), [3, 1]);
t2 = Tensor.Broadcast<int>(t1, [3, 3]);
Assert.Equal([3, 3], t2.Lengths.ToArray());
Assert.Equal([3, 3], t2.Lengths);

Assert.Equal(0, t2[0, 0]);
Assert.Equal(0, t2[0, 1]);
Expand All @@ -789,11 +789,11 @@ public static void TensorBroadcastTests()
Assert.Equal(2, s1[2, 2]);

var t3 = t2.Slice(0..1, ..);
Assert.Equal([1, 3], t3.Lengths.ToArray());
Assert.Equal([1, 3], t3.Lengths);

t1 = Tensor.Create(Enumerable.Range(0, 3), default);
t2 = Tensor.Broadcast<int>(t1, [3, 3]);
Assert.Equal([3, 3], t2.Lengths.ToArray());
Assert.Equal([3, 3], t2.Lengths);

Assert.Equal(0, t2[0, 0]);
Assert.Equal(1, t2[0, 1]);
Expand All @@ -811,15 +811,15 @@ public static void TensorResizeTests()
{
Tensor<int> t0 = Tensor.Create(Enumerable.Range(0, 8), [2, 2, 2]);
var t1 = Tensor.Resize(t0, [1]);
Assert.Equal([1], t1.Lengths.ToArray());
Assert.Equal([1], t1.Lengths);
Assert.Equal(0, t1[0]);

t1 = Tensor.Resize(t0, [1, 1]);
Assert.Equal([1, 1], t1.Lengths.ToArray());
Assert.Equal([1, 1], t1.Lengths);
Assert.Equal(0, t1[0, 0]);

t1 = Tensor.Resize(t0, [6]);
Assert.Equal([6], t1.Lengths.ToArray());
Assert.Equal([6], t1.Lengths);
Assert.Equal(0, t1[0]);
Assert.Equal(1, t1[1]);
Assert.Equal(2, t1[2]);
Expand All @@ -828,7 +828,7 @@ public static void TensorResizeTests()
Assert.Equal(5, t1[5]);

t1 = Tensor.Resize(t0, [10]);
Assert.Equal([10], t1.Lengths.ToArray());
Assert.Equal([10], t1.Lengths);
Assert.Equal(0, t1[0]);
Assert.Equal(1, t1[1]);
Assert.Equal(2, t1[2]);
Expand All @@ -841,7 +841,7 @@ public static void TensorResizeTests()
Assert.Equal(0, t1[9]);

t1 = Tensor.Resize(t0, [2, 5]);
Assert.Equal([2, 5], t1.Lengths.ToArray());
Assert.Equal([2, 5], t1.Lengths);
Assert.Equal(0, t1[0, 0]);
Assert.Equal(1, t1[0, 1]);
Assert.Equal(2, t1[0, 2]);
Expand All @@ -859,8 +859,8 @@ public static void TensorSplitTests()
{
Tensor<int> t0 = Tensor.Create(Enumerable.Range(0, 8), [2, 2, 2]);
var t1 = Tensor.Split<int>(t0, 2, 0);
Assert.Equal([1, 2, 2], t1[0].Lengths.ToArray());
Assert.Equal([1, 2, 2], t1[1].Lengths.ToArray());
Assert.Equal([1, 2, 2], t1[0].Lengths);
Assert.Equal([1, 2, 2], t1[1].Lengths);
Assert.Equal(0, t1[0][0, 0, 0]);
Assert.Equal(1, t1[0][0, 0, 1]);
Assert.Equal(2, t1[0][0, 1, 0]);
Expand All @@ -871,8 +871,8 @@ public static void TensorSplitTests()
Assert.Equal(7, t1[1][0, 1, 1]);

t1 = Tensor.Split<int>(t0, 2, 1);
Assert.Equal([2, 1, 2], t1[0].Lengths.ToArray());
Assert.Equal([2, 1, 2], t1[1].Lengths.ToArray());
Assert.Equal([2, 1, 2], t1[0].Lengths);
Assert.Equal([2, 1, 2], t1[1].Lengths);
Assert.Equal(0, t1[0][0, 0, 0]);
Assert.Equal(1, t1[0][0, 0, 1]);
Assert.Equal(4, t1[0][1, 0, 0]);
Expand All @@ -883,8 +883,8 @@ public static void TensorSplitTests()
Assert.Equal(7, t1[1][1, 0, 1]);

t1 = Tensor.Split<int>(t0, 2, 2);
Assert.Equal([2, 2, 1], t1[0].Lengths.ToArray());
Assert.Equal([2, 2, 1], t1[1].Lengths.ToArray());
Assert.Equal([2, 2, 1], t1[0].Lengths);
Assert.Equal([2, 2, 1], t1[1].Lengths);
Assert.Equal(0, t1[0][0, 0, 0]);
Assert.Equal(2, t1[0][0, 1, 0]);
Assert.Equal(4, t1[0][1, 0, 0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ProjectReference Include="$(CoreLibProject)" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime\src\System.Runtime.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Collections\src\System.Collections.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Memory\src\System.Memory.csproj" />
Copy link
Member Author

@jjonescz jjonescz Oct 11, 2024

Choose a reason for hiding this comment

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

Without this the build would fail with:

error CS0656: Missing compiler required member 'System.MemoryExtensions.AsSpan'

That's because that helper is now used for codegen of the built-in span conversions from string to ReadOnlySpan. Previously the user-defined conversion on string was used, but that's not available on .NET Framework. In this case the conversion is part of interpolated string conversion, so this worked previously because a different interpolated string builder overload was chosen that didn't need the string->span conversion (the compiler doesn't gate the overload resolution by whether the codegen helpers exist).

Copy link
Member

Choose a reason for hiding this comment

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

I'm not understanding this one. For .NET Framework, Span itself is part of the System.Memory package. How could you be in a situation where you're using Span on netfx but don't have the System.Memory reference in your transitive closure?

Copy link
Member Author

@jjonescz jjonescz Oct 14, 2024

Choose a reason for hiding this comment

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

Maybe it's just some weirdness of this project. It has a reference to Span via src\libraries\System.Runtime\ref\System.Runtime.cs. That contains definition of Span but not MemoryExtensions.

<ProjectReference Include="$(LibrariesProjectRoot)System.Threading\src\System.Threading.csproj" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public void VisualBasicReverseString()
// Arrange

string forwardActual = string.Concat(clusters.SelectMany(cluster => cluster).Select(rune => rune.ToString()));
string reverseExpected = string.Concat(clusters.Reverse().SelectMany(cluster => cluster).Select(rune => rune.ToString()));
string reverseExpected = string.Concat(Enumerable.Reverse(clusters).SelectMany(cluster => cluster).Select(rune => rune.ToString()));

// Act

Expand Down
Loading