Skip to content

Commit

Permalink
Use existing feature switch
Browse files Browse the repository at this point in the history
  • Loading branch information
MichalStrehovsky committed Feb 3, 2025
1 parent 8aafda6 commit 05d43cf
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 50 deletions.
3 changes: 0 additions & 3 deletions src/libraries/System.Linq/src/System/Linq/Enumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,5 @@ internal static bool TryGetSpan<TSource>(this IEnumerable<TSource> source, out R

return result;
}

[FeatureSwitchDefinition("System.Linq.Enumerable.ValueTypeTrimFriendlySelect")]
internal static bool ValueTypeTrimFriendlySelect { get; } = AppContext.TryGetSwitch("System.Linq.Enumerable.ValueTypeTrimFriendlySelect", out bool isEnabled) ? isEnabled : false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> s
new IEnumerableWhereSelectIterator<object, TResult2>(objectSource, isTResult, localSelector);
}

return new IteratorSelectIterator<TResult, TResult2>(this, selector);
return base.Select(selector);
}
}
}
Expand Down
33 changes: 13 additions & 20 deletions src/libraries/System.Linq/src/System/Linq/Select.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using static System.Linq.Utilities;

namespace System.Linq
Expand All @@ -26,7 +25,19 @@ public static IEnumerable<TResult> Select<TSource, TResult>(

if (source is Iterator<TSource> iterator)
{
return SelectImplementation(selector, iterator);
// With native AOT, calling into the `Select` generic virtual method results in NxM
// expansion of native code. If the option is enabled, we don't call the generic virtual
// for value types. We don't do the same for reference types because reference type
// expansion can happen lazily at runtime and the AOT compiler does postpone it (we
// don't need more code, just more data structures describing the new types).
if (IsSizeOptimized && typeof(TResult).IsValueType)
{
return new IEnumerableSelectIterator<TSource, TResult>(iterator, selector);
}
else
{
return iterator.Select(selector);
}
}

if (source is IList<TSource> ilist)
Expand All @@ -52,24 +63,6 @@ public static IEnumerable<TResult> Select<TSource, TResult>(
return new IEnumerableSelectIterator<TSource, TResult>(source, selector);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static IEnumerable<TResult> SelectImplementation<TSource, TResult>(Func<TSource, TResult> selector, Iterator<TSource> iterator)
{
// With native AOT, calling into the `Select` generic virtual method results in NxM
// expansion of native code. If the option is enabled, we don't call the generic virtual
// for value types. We don't do the same for reference types because reference type
// expansion can happen lazily at runtime and the AOT compiler does postpone it (we
// don't need more code, just more data structures describing the new types).
if (ValueTypeTrimFriendlySelect && typeof(TResult).IsValueType)
{
if (IsSizeOptimized)
return new IEnumerableSelectIterator<TSource, TResult>(iterator, selector);
return new IteratorSelectIterator<TSource, TResult>(iterator, selector);
}

return iterator.Select(selector);
}

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
if (source is null)
Expand Down
30 changes: 5 additions & 25 deletions src/libraries/System.Linq/tests/SkipWhileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;

namespace System.Linq.Tests
Expand Down Expand Up @@ -61,31 +60,12 @@ public void RunOnce()
Assert.Equal(Enumerable.Range(10, 10), Enumerable.Range(0, 20).RunOnce().SkipWhile((i, idx) => idx < 10));
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public static void SkipErrorWhenSourceErrors_TrimFriendlySelectTrue()
{
RemoteExecutor.Invoke(() =>
{
AppContext.SetSwitch("System.Linq.Enumerable.ValueTypeTrimFriendlySelect", true);

var source = NumberRangeGuaranteedNotCollectionType(-2, 5).Select(i => (decimal)i).Select(m => 1 / m).Skip(4);
var valuesFromEnumerable = source.ToList();
List<decimal> expectedValues = [(decimal)1/2];
Assert.Equal(expectedValues, valuesFromEnumerable);
}).Dispose();
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void SkipErrorWhenSourceErrors_TrimFriendlySelectFalse()
[Fact]
public void SkipErrorWhenSourceErrors()
{
RemoteExecutor.Invoke(() =>
{
AppContext.SetSwitch("System.Linq.Enumerable.ValueTypeTrimFriendlySelect", false);

var source = NumberRangeGuaranteedNotCollectionType(-2, 5).Select(i => (decimal)i).Select(m => 1 / m).Skip(4);
using var en = source.GetEnumerator();
Assert.Throws<DivideByZeroException>(() => en.MoveNext());
}).Dispose();
var source = NumberRangeGuaranteedNotCollectionType(-2, 5).Select(i => (decimal)i).Select(m => 1 / m).Skip(4);
using var en = source.GetEnumerator();
Assert.Throws<DivideByZeroException>(() => en.MoveNext());
}

[Fact]
Expand Down
1 change: 0 additions & 1 deletion src/libraries/System.Linq/tests/System.Linq.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<DebuggerSupport Condition="'$(DebuggerSupport)' == '' and '$(TargetOS)' == 'browser'">true</DebuggerSupport>
</PropertyGroup>
Expand Down

0 comments on commit 05d43cf

Please # to comment.