From bec267092ee09dd14032a6d08eae1be22d9858c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:37:55 -0700 Subject: [PATCH 001/345] [release/8.0] Bump to RC2 (#90557) * [release/8.0] Bump to RC2 Bump the base release/8.0 branch to target RC2. * Set prerelease to 0 in configureplatform.make --- eng/Versions.props | 2 +- eng/native/configureplatform.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 3cccff5761371c..8b6faffed23598 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -10,7 +10,7 @@ 7.0.8 6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11)) rc - 1 + 2 -$(PreReleaseVersionLabel).$(PreReleaseVersionIteration) $(SdkBandVersion)$(WorkloadVersionSuffix) - + false true - 113.0.5672.63 - 1121455 - <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1121461 + 115.0.5790.170 + 1148114 + <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1148123 - 113.0.5672.64 - 1121455 - <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1121477 + 115.0.5790.171 + 1148114 + <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1148119 From 94f0a7167cfd8fdf9387e57045473190281e1bb9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 18:24:12 -0700 Subject: [PATCH 007/345] [release/8.0-rc1] [mono][ios] Revert LLVM mode for apple mobile tests (#90624) * Revert LLVM mode for apple mobile tests * Add comment --------- Co-authored-by: Milos Kotlar --- eng/testing/tests.ioslike.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/testing/tests.ioslike.targets b/eng/testing/tests.ioslike.targets index 9151c7c7db05e5..f93afcf1dfb31b 100644 --- a/eng/testing/tests.ioslike.targets +++ b/eng/testing/tests.ioslike.targets @@ -15,8 +15,8 @@ <_AOTBuildCommand Condition="'$(ContinuousIntegrationBuild)' != 'true'">$(_AOTBuildCommand) /p:RuntimeSrcDir=$(RepoRoot) /p:RuntimeConfig=$(Configuration) - - <_AOTBuildCommand>$(_AOTBuildCommand) /p:XHARNESS_EXECUTION_DIR="$XHARNESS_EXECUTION_DIR" /p:RunAOTCompilation=$(RunAOTCompilation) /p:UseNativeAOTRuntime=$(UseNativeAOTRuntime) /p:TargetOS=$(TargetOS) /p:TargetArchitecture=$(TargetArchitecture) /p:MonoForceInterpreter=$(MonoForceInterpreter) /p:DevTeamProvisioning=$(DevTeamProvisioning) /p:UsePortableRuntimePack=true /p:Configuration=$(Configuration) + + <_AOTBuildCommand>$(_AOTBuildCommand) /p:XHARNESS_EXECUTION_DIR="$XHARNESS_EXECUTION_DIR" /p:RunAOTCompilation=$(RunAOTCompilation) /p:UseNativeAOTRuntime=$(UseNativeAOTRuntime) /p:TargetOS=$(TargetOS) /p:TargetArchitecture=$(TargetArchitecture) /p:MonoForceInterpreter=$(MonoForceInterpreter) /p:MonoEnableLLVM=true /p:DevTeamProvisioning=$(DevTeamProvisioning) /p:UsePortableRuntimePack=true /p:Configuration=$(Configuration) <_AOTBuildCommand>$(_AOTBuildCommand) <_ResetSimulatorSwitch Condition="'$(TargetOS)' == 'iossimulator' or '$(TargetOS)' == 'tvossimulator'">--reset-simulator From 6222fca7914de6790a96079c75021b8263a87ad0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 21:50:33 -0700 Subject: [PATCH 008/345] [release/8.0-rc1] [workloads] Put quotes around GetFileName call when collecting telemetry (#90606) * [workloads] Put quotes around GetFileName call when collecting telemetry There are cases where `%(ReferencePath)` is empty, so prevent exceptions by quoting the value. Fixes https://github.com/dotnet/runtime/issues/90584 * Feedback --------- Co-authored-by: Steve Pfister Co-authored-by: Steve Pfister --- .../WorkloadTelemetry.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets index f9cd6efe170a2c..8f78ce16b62587 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets @@ -38,8 +38,8 @@ - <_WorkloadUsesOther Condition="'$([System.IO.Path]::GetFileName(%(ReferencePath.Identity)).ToLower())' == 'avalonia.dll'">true - <_WorkloadUsesOther Condition="'$([System.IO.Path]::GetFileName(%(ReferencePath.Identity)).ToLower())' == 'uno.dll'">true + <_WorkloadUsesOther Condition="'$([System.IO.Path]::GetFileName("%(ReferencePath.Identity)").ToLowerInvariant())' == 'avalonia.dll'">true + <_WorkloadUsesOther Condition="'$([System.IO.Path]::GetFileName("%(ReferencePath.Identity)").ToLowerInvariant())' == 'uno.dll'">true <_WorkloadUsesMobileSDKOnly Condition="'$(RuntimeIdentifier)' != 'browser-wasm' and '$(UseMaui)' != 'true' and '$(_WorkloadUsesOther)' != 'true'">true From b1225e7c0902f82362afc9cc21b632462a9339b4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:17:22 -0700 Subject: [PATCH 009/345] Update dependencies from https://github.com/dotnet/emsdk build 20230815.5 (#90649) Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.1.23411.2 -> To Version 8.0.0-rc.1.23415.5 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 76bf5019cd8ed2..e31341152d13b0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,9 +90,9 @@ 2f4ef297939628143389ddeea569874ded0b1c1b - + https://github.com/dotnet/emsdk - abfa03c97f4175d4d209435cd0e71f558e36c3fd + 66dbaefff04250dc72849f0172e0c53bcfb3ab38 diff --git a/eng/Versions.props b/eng/Versions.props index 3cccff5761371c..ff21c1ee1f07dc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -238,7 +238,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.1.23411.2 + 8.0.0-rc.1.23415.5 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From b33c596d0dd56b509ad4ad144985d00e21d08035 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:26:12 -0700 Subject: [PATCH 010/345] [release/8.0] Return false from ComWrappers.Try... methods (#90635) * Return false from ComWrappers.Try... methods Return false from ComWrappers.TryGetComInstance/TryGetObject instead of throwing PNSE. It saves callers from needing to protect against PNSE. Fix #90311 * More efficient IsWindows check --------- Co-authored-by: Jan Kotas --- .../src/System/ComponentModel/TypeDescriptor.cs | 2 +- .../InteropServices/ComWrappers.PlatformNotSupported.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs index 874fa6e2e7d03e..2efd53e6223ae7 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs @@ -1542,7 +1542,7 @@ private static TypeDescriptionNode NodeFor(object instance, bool createDelegator { type = ComObjectType; } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + else if (OperatingSystem.IsWindows() && ComWrappers.TryGetComInstance(instance, out nint unknown)) { // ComObjectType uses the Windows Forms provided ComNativeDescriptor. It currently has hard Win32 diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs index 2d2a812cb41a07..37c25f851538a7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs @@ -11,12 +11,14 @@ public abstract partial class ComWrappers { public static unsafe bool TryGetComInstance(object obj, out IntPtr unknown) { - throw new PlatformNotSupportedException(); + unknown = default; + return false; } public static unsafe bool TryGetObject(IntPtr unknown, [NotNullWhen(true)] out object? obj) { - throw new PlatformNotSupportedException(); + obj = default; + return false; } public partial struct ComInterfaceDispatch From d29067bc3bc614ed08a5e6cd94baff0481f435e6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:38:41 -0700 Subject: [PATCH 011/345] [release/8.0-rc1] Fix support for non-public default constructors using JsonIncludeAttribute (#90615) * Fix support for non-public constructors using JsonIncludeAttribute * Address feedback. --------- Co-authored-by: Eirik Tsarpalis --- .../DefaultJsonTypeInfoResolver.Helpers.cs | 21 ++++++++++++++- .../Serialization/Metadata/MemberAccessor.cs | 5 ++-- .../ReflectionEmitCachingMemberAccessor.cs | 6 ++--- .../Metadata/ReflectionEmitMemberAccessor.cs | 15 ++++++----- .../Metadata/ReflectionMemberAccessor.cs | 27 +++++++------------ .../ConstructorTests.AttributePresence.cs | 18 +++++++++++++ .../TestClasses/TestClasses.Constructor.cs | 27 +++++++++++++++++++ .../Serialization/ConstructorTests.cs | 6 +++++ 8 files changed, 95 insertions(+), 30 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs index 7ec9db9adc7739..8ee9f3db0283b4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs @@ -49,7 +49,7 @@ private static JsonTypeInfo CreateTypeInfoCore(Type type, JsonConverter converte typeInfo.PopulatePolymorphismMetadata(); typeInfo.MapInterfaceTypesToCallbacks(); - Func? createObject = MemberAccessor.CreateConstructor(typeInfo.Type); + Func? createObject = DetermineCreateObjectDelegate(type, converter); typeInfo.SetCreateObjectIfCompatible(createObject); typeInfo.CreateObjectForExtensionDataProperty = createObject; @@ -411,5 +411,24 @@ internal static void DeterminePropertyAccessors(JsonPropertyInfo jsonPrope break; } } + + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)] + private static Func? DetermineCreateObjectDelegate(Type type, JsonConverter converter) + { + ConstructorInfo? defaultCtor = null; + + if (converter.ConstructorInfo != null && !converter.ConstructorIsParameterized) + { + // A parameterless constructor has been resolved by the converter + // (e.g. it might be a non-public ctor with JsonConverterAttribute). + defaultCtor = converter.ConstructorInfo; + } + + // Fall back to resolving any public constructors on the type. + defaultCtor ??= type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null); + + return MemberAccessor.CreateParameterlessConstructor(type, defaultCtor); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/MemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/MemberAccessor.cs index 326ab657b8899d..ff6c442fa488cb 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/MemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/MemberAccessor.cs @@ -9,8 +9,9 @@ namespace System.Text.Json.Serialization.Metadata { internal abstract class MemberAccessor { - public abstract Func? CreateConstructor( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type classType); + public abstract Func? CreateParameterlessConstructor( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, + ConstructorInfo? constructorInfo); public abstract Func CreateParameterizedConstructor(ConstructorInfo constructor); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitCachingMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitCachingMemberAccessor.cs index a243f4be4d86a6..e30f87d76da9f1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitCachingMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitCachingMemberAccessor.cs @@ -21,12 +21,12 @@ internal sealed partial class ReflectionEmitCachingMemberAccessor : MemberAccess => s_cache.GetOrAdd((nameof(CreateAddMethodDelegate), typeof(TCollection), null), static (_) => s_sourceAccessor.CreateAddMethodDelegate()); - public override Func? CreateConstructor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type classType) - => s_cache.GetOrAdd((nameof(CreateConstructor), classType, null), + public override Func? CreateParameterlessConstructor([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, ConstructorInfo? ctorInfo) + => s_cache.GetOrAdd((nameof(CreateParameterlessConstructor), type, ctorInfo), [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2077:UnrecognizedReflectionPattern", Justification = "Cannot apply DynamicallyAccessedMembersAttribute to tuple properties.")] #pragma warning disable IL2077 // The suppression doesn't work for the trim analyzer: https://github.com/dotnet/roslyn/issues/59746 - static (key) => s_sourceAccessor.CreateConstructor(key.declaringType)); + static (key) => s_sourceAccessor.CreateParameterlessConstructor(key.declaringType, (ConstructorInfo?)key.member)); #pragma warning restore IL2077 public override Func CreateFieldGetter(FieldInfo fieldInfo) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitMemberAccessor.cs index 6e05e5c8057ac7..4b0b426bdaa9ef 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionEmitMemberAccessor.cs @@ -13,18 +13,19 @@ namespace System.Text.Json.Serialization.Metadata [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)] internal sealed class ReflectionEmitMemberAccessor : MemberAccessor { - public override Func? CreateConstructor( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + public override Func? CreateParameterlessConstructor( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, + ConstructorInfo? constructorInfo) { Debug.Assert(type != null); - ConstructorInfo? realMethod = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null); + Debug.Assert(constructorInfo is null || constructorInfo.GetParameters().Length == 0); if (type.IsAbstract) { return null; } - if (realMethod == null && !type.IsValueType) + if (constructorInfo is null && !type.IsValueType) { return null; } @@ -38,8 +39,10 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor ILGenerator generator = dynamicMethod.GetILGenerator(); - if (realMethod == null) + if (constructorInfo is null) { + Debug.Assert(type.IsValueType); + LocalBuilder local = generator.DeclareLocal(type); generator.Emit(OpCodes.Ldloca_S, local); @@ -49,7 +52,7 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor } else { - generator.Emit(OpCodes.Newobj, realMethod); + generator.Emit(OpCodes.Newobj, constructorInfo); if (type.IsValueType) { // Since C# 10 it's now possible to have parameterless constructors in structs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionMemberAccessor.cs index 606ad6aba79c26..8627a24f3f4926 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionMemberAccessor.cs @@ -10,35 +10,26 @@ namespace System.Text.Json.Serialization.Metadata { internal sealed class ReflectionMemberAccessor : MemberAccessor { - private sealed class ConstructorContext - { - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] - private readonly Type _type; - - public ConstructorContext([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) - => _type = type; - - public object? CreateInstance() - => Activator.CreateInstance(_type, nonPublic: false); - } - - public override Func? CreateConstructor( - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + public override Func? CreateParameterlessConstructor( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, + ConstructorInfo? ctorInfo) { Debug.Assert(type != null); - ConstructorInfo? realMethod = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, binder: null, Type.EmptyTypes, modifiers: null); + Debug.Assert(ctorInfo is null || ctorInfo.GetParameters().Length == 0); if (type.IsAbstract) { return null; } - if (realMethod == null && !type.IsValueType) + if (ctorInfo is null) { - return null; + return type.IsValueType + ? () => Activator.CreateInstance(type, nonPublic: false)! + : null; } - return new ConstructorContext(type).CreateInstance!; + return () => ctorInfo.Invoke(null); } public override Func CreateParameterizedConstructor(ConstructorInfo constructor) diff --git a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.AttributePresence.cs b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.AttributePresence.cs index 681d495b8c752c..f54692a5c59a44 100644 --- a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.AttributePresence.cs +++ b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.AttributePresence.cs @@ -39,6 +39,24 @@ public async Task NonPublicCtors_WithJsonConstructorAttribute_WorksAsExpected(Ty } } + [Theory] + [InlineData(typeof(PrivateParameterlessCtor_WithAttribute), false)] + [InlineData(typeof(InternalParameterlessCtor_WithAttribute), true)] + [InlineData(typeof(ProtectedParameterlessCtor_WithAttribute), false)] + public async Task NonPublicParameterlessCtors_WithJsonConstructorAttribute_WorksAsExpected(Type type, bool isAccessibleBySourceGen) + { + if (!Serializer.IsSourceGeneratedSerializer || isAccessibleBySourceGen) + { + object? result = await Serializer.DeserializeWrapper("{}", type); + Assert.IsType(type, result); + } + else + { + NotSupportedException ex = await Assert.ThrowsAsync(() => Serializer.DeserializeWrapper("{}", type)); + Assert.Contains("JsonConstructorAttribute", ex.ToString()); + } + } + [Fact] public async Task SinglePublicParameterizedCtor_SingleParameterlessCtor_NoAttribute_Supported_UseParameterlessCtor() { diff --git a/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.Constructor.cs b/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.Constructor.cs index 285c5b78934733..f12cf89e41de59 100644 --- a/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.Constructor.cs +++ b/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.Constructor.cs @@ -74,6 +74,33 @@ public class ProtectedParameterizedCtor_WithAttribute protected ProtectedParameterizedCtor_WithAttribute(int x) => X = x; } + public class PrivateParameterlessCtor_WithAttribute + { + public int X { get; } + + [JsonConstructor] + private PrivateParameterlessCtor_WithAttribute() + => X = 42; + } + + public class ProtectedParameterlessCtor_WithAttribute + { + public int X { get; } + + [JsonConstructor] + protected ProtectedParameterlessCtor_WithAttribute() + => X = 42; + } + + public class InternalParameterlessCtor_WithAttribute + { + public int X { get; } + + [JsonConstructor] + internal InternalParameterlessCtor_WithAttribute() + => X = 42; + } + public class PrivateParameterlessCtor_InternalParameterizedCtor_WithMultipleAttributes { [JsonConstructor] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs index b2a5fd465da766..d1769f491104db 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs @@ -41,6 +41,9 @@ protected ConstructorTests_Metadata(JsonSerializerWrapper stringWrapper) [JsonSerializable(typeof(PrivateParameterizedCtor_WithAttribute))] [JsonSerializable(typeof(InternalParameterizedCtor_WithAttribute))] [JsonSerializable(typeof(ProtectedParameterizedCtor_WithAttribute))] + [JsonSerializable(typeof(PrivateParameterlessCtor_WithAttribute))] + [JsonSerializable(typeof(InternalParameterlessCtor_WithAttribute))] + [JsonSerializable(typeof(ProtectedParameterlessCtor_WithAttribute))] [JsonSerializable(typeof(SinglePublicParameterizedCtor))] [JsonSerializable(typeof(SingleParameterlessCtor_MultiplePublicParameterizedCtor))] [JsonSerializable(typeof(SingleParameterlessCtor_MultiplePublicParameterizedCtor_Struct))] @@ -186,6 +189,9 @@ public ConstructorTests_Default(JsonSerializerWrapper jsonSerializer) : base(jso [JsonSerializable(typeof(PrivateParameterizedCtor_WithAttribute))] [JsonSerializable(typeof(InternalParameterizedCtor_WithAttribute))] [JsonSerializable(typeof(ProtectedParameterizedCtor_WithAttribute))] + [JsonSerializable(typeof(PrivateParameterlessCtor_WithAttribute))] + [JsonSerializable(typeof(InternalParameterlessCtor_WithAttribute))] + [JsonSerializable(typeof(ProtectedParameterlessCtor_WithAttribute))] [JsonSerializable(typeof(SinglePublicParameterizedCtor))] [JsonSerializable(typeof(SingleParameterlessCtor_MultiplePublicParameterizedCtor))] [JsonSerializable(typeof(SingleParameterlessCtor_MultiplePublicParameterizedCtor_Struct))] From c79f02af08949a0b2d7b61e5fa40323eb31b64c8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 08:32:09 -0700 Subject: [PATCH 012/345] [release/8.0-rc1] Annotate System.Linq.Expressions with RequiresDynamicCode (#90616) * Annotate System.Linq.Expressions with RequiresDynamicCode All this ended up with an RUC on Expression.Compile due to new arrays. I could potentially silence this warning with a feature flag, but it is a real risk, and one that users could maybe work around if alterted to the problem. * Remove suppression that's no longer needed * Fix tests for new feature switch behavior * Update src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Expression.cs Co-authored-by: Eric Erhardt * Typo in Throws call * Fix assert for net framework * Respond to PR comments * Add suppression * Typo * Update src/libraries/System.Linq.Expressions/src/Resources/Strings.resx Co-authored-by: Stephen Toub * PR feedback --------- Co-authored-by: Andy Gocke Co-authored-by: Andy Gocke Co-authored-by: Eric Erhardt Co-authored-by: Stephen Toub --- .../TestUtilities/System/AssertExtensions.cs | 21 +++++++ .../Expressions/ExpressionResolverBuilder.cs | 11 +++- .../ref/System.Linq.Expressions.cs | 5 ++ .../src/CompatibilitySuppressions.xml | 42 +++++++++++++ .../src/Resources/Strings.resx | 3 + .../src/System.Linq.Expressions.csproj | 2 +- .../src/System/Dynamic/DynamicObject.cs | 9 ++- .../Dynamic/Utils/CachedReflectionInfo.cs | 32 ---------- .../System/Dynamic/Utils/DelegateHelpers.cs | 9 ++- .../src/System/Dynamic/Utils/TypeUtils.cs | 62 +++++++++++++++++++ .../Linq/Expressions/BinaryExpression.cs | 8 ++- .../Linq/Expressions/Compiler/AssemblyGen.cs | 1 + .../Compiler/CompilerScope.Storage.cs | 3 + .../Expressions/Compiler/CompilerScope.cs | 3 + .../Expressions/Compiler/DelegateHelpers.cs | 3 + .../Compiler/LambdaCompiler.Binary.cs | 3 +- .../Expressions/Compiler/LambdaCompiler.cs | 2 + .../Linq/Expressions/Compiler/StackSpiller.cs | 1 + .../Expressions/Compiler/VariableBinder.cs | 1 + .../src/System/Linq/Expressions/Expression.cs | 5 ++ .../Interpreter/ArrayOperations.cs | 5 ++ .../Interpreter/InstructionList.cs | 9 +-- .../Expressions/Interpreter/LightCompiler.cs | 4 ++ .../Linq/Expressions/LambdaExpression.cs | 11 ++++ .../Linq/Expressions/ListInitExpression.cs | 4 ++ .../Linq/Expressions/MethodCallExpression.cs | 4 ++ .../Linq/Expressions/NewArrayExpression.cs | 15 +++++ .../src/System/Linq/Expressions/Strings.cs | 8 +++ .../Linq/Expressions/UnaryExpression.cs | 4 +- .../Runtime/CompilerServices/CallSite.cs | 53 ++++++++++++---- .../CompilerServices/CallSiteBinder.cs | 4 +- .../Runtime/CompilerServices/CallSiteOps.cs | 3 + .../CallSiteOpsReflectionCache.cs | 37 +++++++++++ .../Arithmetic/BinaryMultiplyTests.cs | 38 +++++++----- .../tests/HelperTypes.cs | 2 + .../Lifted/LiftedAddCheckedNullableTests.cs | 13 ++-- .../tests/Lifted/LiftedAddNullableTests.cs | 13 ++-- .../Lifted/LiftedBitwiseAndNullableTests.cs | 13 ++-- .../LiftedBitwiseExclusiveOrNullableTests.cs | 13 ++-- .../Lifted/LiftedBitwiseOrNullableTests.cs | 13 ++-- .../tests/Lifted/LiftedDivideNullableTests.cs | 13 ++-- .../tests/Lifted/LiftedModuloNullableTests.cs | 13 ++-- .../LiftedMultiplyCheckedNullableTests.cs | 13 ++-- .../Lifted/LiftedMultiplyNullableTests.cs | 13 ++-- .../LiftedSubtractCheckedNullableTests.cs | 13 ++-- .../Lifted/LiftedSubtractNullableTests.cs | 13 ++-- .../tests/SequenceTests/SequenceTests.cs | 12 ++-- .../Unary/UnaryDecrementNullableTests.cs | 20 +++--- .../tests/Unary/UnaryDecrementTests.cs | 2 +- .../Unary/UnaryIncrementNullableTests.cs | 20 +++--- 50 files changed, 468 insertions(+), 156 deletions(-) create mode 100644 src/libraries/System.Linq.Expressions/src/System/Runtime/CompilerServices/CallSiteOpsReflectionCache.cs diff --git a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs index bf676b7b6f26be..230e4cb4276a42 100644 --- a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs +++ b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -15,6 +16,26 @@ public static class AssertExtensions { private static bool IsNetFramework => RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework"); + + /// + /// Helper for AOT tests that verifies that the compile succeeds, or throws PlatformNotSupported + /// when AOT is enabled. + /// + public static void ThrowsOnAot(Action action) + where T : Exception + { +#if NETCOREAPP // Dynamic code is always supported on .NET Framework + if (!RuntimeFeature.IsDynamicCodeSupported) + { + Assert.Throws(action); + } + else +#endif + { + action(); + } + } + public static void Throws(Action action, string expectedMessage) where T : Exception { diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs index c28b9f00bb4e7d..670c62ee2f69a8 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs @@ -123,6 +123,15 @@ static MethodInfo GetArrayEmptyMethodInfo(Type elementType) return ServiceLookupHelpers.GetArrayEmptyMethodInfo(elementType); } + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "VerifyAotCompatibility ensures elementType is not a ValueType")] + static NewArrayExpression NewArrayInit(Type elementType, IEnumerable expr) + { + Debug.Assert(!ServiceProvider.VerifyAotCompatibility || !elementType.IsValueType, "VerifyAotCompatibility=true will throw during building the IEnumerableCallSite if elementType is a ValueType."); + + return Expression.NewArrayInit(elementType, expr); + } + if (callSite.ServiceCallSites.Length == 0) { return Expression.Constant( @@ -130,7 +139,7 @@ static MethodInfo GetArrayEmptyMethodInfo(Type elementType) .Invoke(obj: null, parameters: Array.Empty())); } - return Expression.NewArrayInit( + return NewArrayInit( callSite.ItemType, callSite.ServiceCallSites.Select(cs => Convert( diff --git a/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs b/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs index 98bfd460ddb960..015cfb079d360a 100644 --- a/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs +++ b/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs @@ -607,9 +607,13 @@ protected Expression(System.Linq.Expressions.ExpressionType nodeType, System.Typ public static System.Linq.Expressions.NewExpression New(System.Reflection.ConstructorInfo constructor, System.Collections.Generic.IEnumerable? arguments, params System.Reflection.MemberInfo[]? members) { throw null; } public static System.Linq.Expressions.NewExpression New(System.Reflection.ConstructorInfo constructor, params System.Linq.Expressions.Expression[]? arguments) { throw null; } public static System.Linq.Expressions.NewExpression New([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Creating arrays at runtime requires dynamic code generation.")] public static System.Linq.Expressions.NewArrayExpression NewArrayBounds(System.Type type, System.Collections.Generic.IEnumerable bounds) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Creating arrays at runtime requires dynamic code generation.")] public static System.Linq.Expressions.NewArrayExpression NewArrayBounds(System.Type type, params System.Linq.Expressions.Expression[] bounds) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Creating arrays at runtime requires dynamic code generation.")] public static System.Linq.Expressions.NewArrayExpression NewArrayInit(System.Type type, System.Collections.Generic.IEnumerable initializers) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Creating arrays at runtime requires dynamic code generation.")] public static System.Linq.Expressions.NewArrayExpression NewArrayInit(System.Type type, params System.Linq.Expressions.Expression[] initializers) { throw null; } public static System.Linq.Expressions.UnaryExpression Not(System.Linq.Expressions.Expression expression) { throw null; } public static System.Linq.Expressions.UnaryExpression Not(System.Linq.Expressions.Expression expression, System.Reflection.MethodInfo? method) { throw null; } @@ -1028,6 +1032,7 @@ internal MethodCallExpression() { } System.Linq.Expressions.Expression System.Linq.Expressions.IArgumentProvider.GetArgument(int index) { throw null; } public System.Linq.Expressions.MethodCallExpression Update(System.Linq.Expressions.Expression? @object, System.Collections.Generic.IEnumerable? arguments) { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Creating arrays at runtime requires dynamic code generation.")] public partial class NewArrayExpression : System.Linq.Expressions.Expression { internal NewArrayExpression() { } diff --git a/src/libraries/System.Linq.Expressions/src/CompatibilitySuppressions.xml b/src/libraries/System.Linq.Expressions/src/CompatibilitySuppressions.xml index 8185aa8209fa11..bf51da8ccbe294 100644 --- a/src/libraries/System.Linq.Expressions/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Linq.Expressions/src/CompatibilitySuppressions.xml @@ -97,6 +97,48 @@ ref/net8.0/System.Linq.Expressions.dll lib/net8.0/System.Linq.Expressions.dll + + CP0016 + M:System.Linq.Expressions.Expression.Call(System.Linq.Expressions.Expression,System.String,System.Type[],System.Linq.Expressions.Expression[]):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + + + CP0016 + M:System.Linq.Expressions.Expression.Call(System.Type,System.String,System.Type[],System.Linq.Expressions.Expression[]):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + + + CP0016 + M:System.Linq.Expressions.Expression.ListInit(System.Linq.Expressions.NewExpression,System.Collections.Generic.IEnumerable{System.Linq.Expressions.Expression}):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + + + CP0016 + M:System.Linq.Expressions.Expression.ListInit(System.Linq.Expressions.NewExpression,System.Linq.Expressions.Expression[]):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + + + CP0016 + M:System.Linq.Expressions.Expression.ListInit(System.Linq.Expressions.NewExpression,System.Reflection.MethodInfo,System.Collections.Generic.IEnumerable{System.Linq.Expressions.Expression}):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + + + CP0016 + M:System.Linq.Expressions.Expression.ListInit(System.Linq.Expressions.NewExpression,System.Reflection.MethodInfo,System.Linq.Expressions.Expression[]):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + + + CP0016 + M:System.Runtime.CompilerServices.CallSite`1.Create(System.Runtime.CompilerServices.CallSiteBinder):[T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute] + ref/net8.0/System.Linq.Expressions.dll + lib/net8.0/System.Linq.Expressions.dll + CP0020 M:System.Linq.Expressions.DynamicExpressionVisitor.#ctor diff --git a/src/libraries/System.Linq.Expressions/src/Resources/Strings.resx b/src/libraries/System.Linq.Expressions/src/Resources/Strings.resx index 01f6ec7be8ddc5..cfbf09d82e02e9 100644 --- a/src/libraries/System.Linq.Expressions/src/Resources/Strings.resx +++ b/src/libraries/System.Linq.Expressions/src/Resources/Strings.resx @@ -564,4 +564,7 @@ The given key '{0}' was not present in the dictionary. + + Nullable lifting on non-primitive type '{0}' is only supported in expression trees when dynamic code generation is available. + diff --git a/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj b/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj index 47375e1d827797..08f93036a937da 100644 --- a/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj +++ b/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj @@ -3,7 +3,6 @@ $(NetCoreAppCurrent) $(DefineConstants);FEATURE_FAST_CREATE $(NoWarn);CA1859 - false @@ -60,4 +120,7 @@ The meter factory does not allow a custom scope value when creating a meter. - + + Only one wildcard character is allowed in category name. + + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/ListenerSubscriptionTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/ListenerSubscriptionTests.cs index da59cffc28d6a6..a0c5d281bfaa0f 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/ListenerSubscriptionTests.cs +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/ListenerSubscriptionTests.cs @@ -214,13 +214,20 @@ public void RuleCanBeTurnedOffAndOnAgain() [InlineData("", "", "")] [InlineData("*", "", "")] [InlineData("lonG", "", "")] + [InlineData("lonG.", "", "")] [InlineData("lonG*", "", "")] [InlineData("lonG.*", "", "")] + [InlineData("lonG.sil", "", "")] + [InlineData("lonG.sil*", "", "")] [InlineData("lonG.sillY.meteR", "", "")] [InlineData("lonG.sillY.meteR*", "", "")] [InlineData("lonG.sillY.meteR.*", "", "")] + [InlineData("*namE", "", "")] + [InlineData("*.namE", "", "")] + [InlineData("*.sillY.meteR.Name", "", "")] + [InlineData("long*Name", "", "")] + [InlineData("lonG.sillY.meter*MeteR.namE", "", "")] // Shouldn't match, but does, left for compatibility with Logging. [InlineData("lonG.sillY.meteR.namE", "", "")] - [InlineData("lonG.sillY.meteR.namE.*", "", "")] [InlineData("", "instrumenTnamE", "")] [InlineData("lonG.sillY.meteR.namE", "instrumenTnamE", "")] [InlineData("", "", "listeneRnamE")] @@ -237,15 +244,13 @@ public void RuleMatchesTest(string meterName, string instrumentName, string list } [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [InlineData("*.*", "", "")] [InlineData("", "*", "")] [InlineData("", "", "*")] - [InlineData("lonG.", "", "")] - [InlineData("lonG.sil", "", "")] - [InlineData("lonG.sil*", "", "")] [InlineData("sillY.meteR.namE", "", "")] + [InlineData(".*", "", "")] + [InlineData("*.", "", "")] + [InlineData("lonG.sillY.meteR.namE.*", "", "")] [InlineData("namE", "", "")] - [InlineData("*.namE", "", "")] [InlineData("wrongMeter", "", "")] [InlineData("wrongMeter", "InstrumentName", "")] [InlineData("wrongMeter", "", "ListenerName")] @@ -261,6 +266,17 @@ public void RuleMatchesNegativeTest(string meterName, string instrumentName, str }, meterName, instrumentName, listenerName).Dispose(); } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void MultipleWildcardsThrows() + { + RemoteExecutor.Invoke(() => { + var rule = new InstrumentRule("*.*", null, null, MeterScope.Global, enable: true); + var meter = new Meter("Long.Silly.Meter.Name"); + var instrument = meter.CreateCounter("InstrumentName"); + Assert.Throws< InvalidOperationException>(() => ListenerSubscription.RuleMatches(rule, instrument, "ListenerName", new FakeMeterFactory())); + }).Dispose(); + } + [Theory] [MemberData(nameof(IsMoreSpecificTestData))] public void IsMoreSpecificTest(InstrumentRule rule, InstrumentRule? best, bool isLocalScope) @@ -388,3 +404,8 @@ private class FakeMeterFactory : IMeterFactory } } } + +internal class SR +{ + public static string MoreThanOneWildcard => "More than one wildcard is not allowed in a rule."; +} From 543e733ea3d0a89372aa6b68bcd09a2b65df1864 Mon Sep 17 00:00:00 2001 From: Juan Sebastian Hoyos Ayala Date: Wed, 16 Aug 2023 18:06:27 +0000 Subject: [PATCH 014/345] Update Microsoft.DiaSymReader.Native to 16.11.29-beta1.23404.4 --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index ff21c1ee1f07dc..82d85ceaaaada5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -161,7 +161,7 @@ 1.0.0-prerelease.23362.5 1.0.0-prerelease.23362.5 - 16.11.27-beta1.23180.1 + 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 3.0.3 2.1.0 From 4d44f2ff0b2a459042cb2eb509c400db4d226e26 Mon Sep 17 00:00:00 2001 From: Alhad Deshpande <97085048+alhad-deshpande@users.noreply.github.com> Date: Wed, 16 Aug 2023 23:56:28 +0530 Subject: [PATCH 015/345] [ppc64le] performance improvements while branching (#90656) --- src/mono/mono/mini/mini-ppc.c | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/mono/mono/mini/mini-ppc.c b/src/mono/mono/mini/mini-ppc.c index 3b9bdf2bcb985c..b3514123b7e941 100644 --- a/src/mono/mono/mini/mini-ppc.c +++ b/src/mono/mono/mini/mini-ppc.c @@ -297,7 +297,7 @@ gboolean mono_ppc_is_direct_call_sequence (guint32 *code) { #ifdef TARGET_POWERPC64 - g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800420); + g_assert(*code == 0x4e800021 || *code == 0x4e800020 || *code == 0x4e800421 || *code == 0x4e800420); /* the thunk-less direct call sequence: lis/ori/sldi/oris/ori/mtlr/blrl */ if (ppc_opcode (code [-1]) == 31) { /* mtlr */ @@ -2939,7 +2939,7 @@ ppc_patch_full (MonoCompile *cfg, guchar *code, const guchar *target, gboolean i return; } - if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) { + if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800421 || ins == 0x4e800420) { #ifdef TARGET_POWERPC64 #if !defined(PPC_USES_FUNCTION_DESCRIPTOR) handle_thunk (cfg, code, target); @@ -2948,7 +2948,7 @@ ppc_patch_full (MonoCompile *cfg, guchar *code, const guchar *target, gboolean i guint32 *branch_ins; /* the trampoline code will try to patch the blrl, blr, bcctr */ - if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) { + if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800421 || ins == 0x4e800420) { branch_ins = seq; if (ppc_is_load_op (seq [-3]) || ppc_opcode (seq [-3]) == 31) /* ld || lwz || mr */ code -= 32; @@ -2996,7 +2996,7 @@ ppc_patch_full (MonoCompile *cfg, guchar *code, const guchar *target, gboolean i #else guint32 *seq; /* the trampoline code will try to patch the blrl, blr, bcctr */ - if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) { + if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800421 || ins == 0x4e800420) { code -= 12; } /* this is the lis/ori/mtlr/blrl sequence */ @@ -3004,7 +3004,7 @@ ppc_patch_full (MonoCompile *cfg, guchar *code, const guchar *target, gboolean i g_assert ((seq [0] >> 26) == 15); g_assert ((seq [1] >> 26) == 24); g_assert ((seq [2] >> 26) == 31); - g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420); + g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800421 || seq [3] == 0x4e800420); /* FIXME: make this thread safe */ ppc_lis (code, PPC_CALL_REG, (guint32)(target) >> 16); ppc_ori (code, PPC_CALL_REG, PPC_CALL_REG, (guint32)(target) & 0xffff); @@ -3426,8 +3426,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG); cfg->thunk_area += THUNK_SIZE; #endif - ppc_mtlr (code, PPC_CALL_REG); - ppc_blrl (code); + ppc_mtctr (code, PPC_CALL_REG); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); } else { ppc_bl (code, 0); } @@ -3913,8 +3913,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG); cfg->thunk_area += THUNK_SIZE; #endif - ppc_mtlr (code, PPC_CALL_REG); - ppc_blrl (code); + ppc_mtctr (code, PPC_CALL_REG); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); } else { ppc_bl (code, 0); } @@ -3945,9 +3945,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } } #endif - ppc_mtlr (code, ins->sreg1); + ppc_mtctr (code, ins->sreg1); #endif - ppc_blrl (code); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); /* FIXME: this should be handled somewhere else in the new jit */ code = emit_move_return_value (cfg, ins, code); break; @@ -3965,8 +3965,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } else { ppc_ldptr (code, ppc_r12, ins->inst_offset, ins->sreg1); } - ppc_mtlr (code, ppc_r12); - ppc_blrl (code); + ppc_mtctr (code, ppc_r12); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); /* FIXME: this should be handled somewhere else in the new jit */ code = emit_move_return_value (cfg, ins, code); break; @@ -4022,8 +4022,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG); cfg->thunk_area += THUNK_SIZE; #endif - ppc_mtlr (code, PPC_CALL_REG); - ppc_blrl (code); + ppc_mtctr (code, PPC_CALL_REG); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); } else { ppc_bl (code, 0); } @@ -4040,8 +4040,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG); cfg->thunk_area += THUNK_SIZE; #endif - ppc_mtlr (code, PPC_CALL_REG); - ppc_blrl (code); + ppc_mtctr (code, PPC_CALL_REG); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); } else { ppc_bl (code, 0); } @@ -4725,8 +4725,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG); cfg->thunk_area += THUNK_SIZE; #endif - ppc_mtlr (code, PPC_CALL_REG); - ppc_blrl (code); + ppc_mtctr (code, PPC_CALL_REG); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); } else { ppc_bl (code, 0); } @@ -5348,8 +5348,8 @@ mono_arch_emit_prolog (MonoCompile *cfg) ppc_ldr (code, PPC_CALL_REG, 0, PPC_CALL_REG); cfg->thunk_area += THUNK_SIZE; #endif - ppc_mtlr (code, PPC_CALL_REG); - ppc_blrl (code); + ppc_mtctr (code, PPC_CALL_REG); + ppc_bcctrl (code, PPC_BR_ALWAYS, 0); } else { ppc_bl (code, 0); } From 243a5aea6983e8a36abbabd14d4f95bf8123ce5b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 12:27:32 -0600 Subject: [PATCH 016/345] Fix problems with `Assembler::ReflectionNotation()` (#90655) Do more parameter validation, correct buffer size calculations for security-enhanced CRT functions, and avoid memcpy buffer overrun of locale. Co-authored-by: Bruce Forstall --- src/coreclr/ilasm/assem.cpp | 84 ++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/src/coreclr/ilasm/assem.cpp b/src/coreclr/ilasm/assem.cpp index dd2c91ac093acb..2bd90fadb8f916 100644 --- a/src/coreclr/ilasm/assem.cpp +++ b/src/coreclr/ilasm/assem.cpp @@ -1324,7 +1324,12 @@ OPCODE Assembler::DecodeOpcode(const BYTE *pCode, DWORD *pdwLen) char* Assembler::ReflectionNotation(mdToken tk) { + // We break the global static `wzUniBuf` into 2 equal parts: the first part is used for a Unicode + // string, the second part is used for a converted-into-multibyte (MB) string. Note that the MB string + // length is in bytes. char *sz = (char*)&wzUniBuf[dwUniBuf>>1], *pc; + const size_t szSizeBytes = (dwUniBuf * sizeof(WCHAR)) / 2; // sizeof(WCHAR) is 2, so this is just `dwUniBuf` + const size_t cchUniBuf = dwUniBuf / 2; // only use the first 1/2 of wzUniBuf *sz=0; switch(TypeFromToken(tk)) { @@ -1333,7 +1338,7 @@ char* Assembler::ReflectionNotation(mdToken tk) Class *pClass = m_lstClass.PEEK(RidFromToken(tk)-1); if(pClass) { - strcpy_s(sz,dwUniBuf>>1,pClass->m_szFQN); + strcpy_s(sz,szSizeBytes,pClass->m_szFQN); pc = sz; while((pc = strchr(pc,NESTING_SEP)) != NULL) { @@ -1348,31 +1353,80 @@ char* Assembler::ReflectionNotation(mdToken tk) { ULONG N; mdToken tkResScope; - if(SUCCEEDED(m_pImporter->GetTypeRefProps(tk,&tkResScope,wzUniBuf,dwUniBuf>>1,&N))) + if(SUCCEEDED(m_pImporter->GetTypeRefProps(tk,&tkResScope,wzUniBuf,cchUniBuf,&N))) { - WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,sz,dwUniBuf>>1,NULL,NULL); + int ret = WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,sz,szSizeBytes,NULL,NULL); if(TypeFromToken(tkResScope)==mdtAssemblyRef) { AsmManAssembly *pAsmRef = m_pManifest->m_AsmRefLst.PEEK(RidFromToken(tkResScope)-1); if(pAsmRef) { - pc = &sz[strlen(sz)]; - pc+=sprintf_s(pc,(dwUniBuf >> 1),", %s, Version=%d.%d.%d.%d, Culture=",pAsmRef->szName, + // We assume below that if sprintf_s fails due to buffer overrun, + // execution fails fast and sprintf_s doesn't return. + int sprintf_ret; + const size_t szLen = strlen(sz); + pc = &sz[szLen]; + size_t szRemainingSizeBytes = szSizeBytes - szLen; + + sprintf_ret = sprintf_s(pc,szRemainingSizeBytes,", %s, Version=%d.%d.%d.%d, Culture=",pAsmRef->szName, pAsmRef->usVerMajor,pAsmRef->usVerMinor,pAsmRef->usBuild,pAsmRef->usRevision); - ULONG L=0; - if(pAsmRef->pLocale && (L=pAsmRef->pLocale->length())) + pc += sprintf_ret; + szRemainingSizeBytes -= (size_t)sprintf_ret; + + unsigned L=0; + if(pAsmRef->pLocale && ((L=pAsmRef->pLocale->length()) > 0)) + { + // L is in bytes and doesn't include the terminating null. + if (L > (cchUniBuf - 1) * sizeof(WCHAR)) + { + report->error("Locale too long (%d characters, %d allowed).\n",L / sizeof(WCHAR), cchUniBuf - 1); + *sz=0; + break; + } + else if (szRemainingSizeBytes == 0) + { + report->error("TypeRef too long.\n"); + *sz=0; + break; + } + + if (szRemainingSizeBytes > 0) + { + memcpy(wzUniBuf,pAsmRef->pLocale->ptr(),L); + wzUniBuf[L>>1] = 0; + ret = WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,pc,(int)szRemainingSizeBytes,NULL,NULL); + if (ret <= 0) + { + report->error("Locale too long.\n"); + *sz=0; + break; + } + else + { + pc += ret; + szRemainingSizeBytes -= (size_t)ret; + } + } + } + else { - memcpy(wzUniBuf,pAsmRef->pLocale->ptr(),L); - wzUniBuf[L>>1] = 0; - WszWideCharToMultiByte(CP_UTF8,0,wzUniBuf,-1,pc,dwUniBuf>>1,NULL,NULL); + sprintf_ret = sprintf_s(pc,szRemainingSizeBytes,"neutral"); + pc += sprintf_ret; + szRemainingSizeBytes -= (size_t)sprintf_ret; } - else pc+=sprintf_s(pc,(dwUniBuf >> 1),"neutral"); - pc = &sz[strlen(sz)]; - if(pAsmRef->pPublicKeyToken && (L=pAsmRef->pPublicKeyToken->length())) + if(pAsmRef->pPublicKeyToken && ((L=pAsmRef->pPublicKeyToken->length()) > 0)) { - pc+=sprintf_s(pc,(dwUniBuf >> 1),", Publickeytoken="); + sprintf_ret = sprintf_s(pc,szRemainingSizeBytes,", Publickeytoken="); + pc += sprintf_ret; + szRemainingSizeBytes -= (size_t)sprintf_ret; + BYTE* pb = (BYTE*)(pAsmRef->pPublicKeyToken->ptr()); - for(N=0; N> 1),"%2.2x",*pb); + for(unsigned i=0; i Date: Wed, 16 Aug 2023 12:44:08 -0600 Subject: [PATCH 017/345] Fix NullableAttribute illink test failures (#90680) When we started building with preview 7 in 5549f72da3b3cea9e74bb81cfbb0f2d27731fc42, NullableAttribute in these testcases started to use the attribute definition from the framework, instead of generating it into the code. This broke the `--used-attrs-only` optimization because `skip` assemblies (the default for the framework in these testcases) are treated as if all types in them are kept, for the purposes of the `--used-attrs-only` optimization. (The optimization removes attribute instances unless the attribute type is preserved for some other reason). It's not clear what the intended behavior of `--used-attrs-only` is for `skip` assemblies, and the discussion in https://github.com/dotnet/linker/issues/952 indicates that it's considered experimental, so this fixes the failures by using the `link` action. This represents a more realistic scenario since `skip` is mainly used in testing to avoid linking the framework in every testcase. Co-authored-by: Sven Boemer --- .../Attributes/OnlyKeepUsed/NullableOnConstraints.cs | 1 + .../LinqExpressions/CanPreserveNullableCustomOperators.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs index b396bb3b10b568..b5efaa7dbcae0b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/NullableOnConstraints.cs @@ -7,6 +7,7 @@ namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed { [SetupCSharpCompilerToUse ("csc")] [SetupLinkerArgument ("--used-attrs-only", "true")] + [SetupLinkerTrimMode ("link")] public class NullableOnConstraints { public static void Main () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinqExpressions/CanPreserveNullableCustomOperators.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinqExpressions/CanPreserveNullableCustomOperators.cs index 32398f667348c4..ec676fe1332211 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinqExpressions/CanPreserveNullableCustomOperators.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinqExpressions/CanPreserveNullableCustomOperators.cs @@ -5,6 +5,7 @@ namespace Mono.Linker.Tests.Cases.LinqExpressions { [SetupCompileArgument ("/unsafe")] [SetupLinkerArgument ("--used-attrs-only")] + [SetupLinkerTrimMode ("link")] public class CanPreserveNullableCustomOperators { public static void Main () From 7cc25f5d8df703d9ba4c0083de0bd43cf0f059f9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 21:42:28 +0200 Subject: [PATCH 018/345] [release/8.0-rc1] Add missing type forwards (#90673) * Add missing type forwards Fixes https://github.com/dotnet/runtime/issues/90578 IDispatchImplAttribute, IDispatchImplType and SetWin32ContextInIDispatchAttribute were removed with https://github.com/dotnet/runtime/commit/9f1dd1aa499a882453b34d4e8810626423fbfed8 and https://github.com/dotnet/runtime/commit/26a91ad6ac02393c6c7463500c030ec07803c5e6 Those dropped types weren't flagged because APICompat only validates reference assemblies. We have three implementation only shim assemblies: mscorlib, System and System.Data. I verified that no other type forwards were lost between .NET 7 and .NET 8. * Update mscorlib.cs --------- Co-authored-by: Viktor Hofer --- src/libraries/shims/mscorlib/src/mscorlib.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libraries/shims/mscorlib/src/mscorlib.cs b/src/libraries/shims/mscorlib/src/mscorlib.cs index 857e2a83bfc48e..eb77227a1130a0 100644 --- a/src/libraries/shims/mscorlib/src/mscorlib.cs +++ b/src/libraries/shims/mscorlib/src/mscorlib.cs @@ -109,3 +109,9 @@ [assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore<>))] [assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags))] [assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Threading.Tasks.Sources.ValueTaskSourceStatus))] +// These types are required for back-compatibility with .NET Framework and previous versions of .NETCoreApp. --> +[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Reflection.Emit.PEFileKinds))] +[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.AssemblyRegistrationFlags))] +[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.ExporterEventKind))] +[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.RegistrationClassContext))] +[assembly:System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.InteropServices.RegistrationConnectionType))] From 9dc05ee36e47447b7dedb56d06328bfcf3db2d60 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:12:49 -0700 Subject: [PATCH 019/345] Fix gcroot SOS command on arm/arm64 (#90658) Faulted in DAC because the HelperMethodFrame's REGDISPLAY CurrentContextPointers were not initialized correctly. Fixes issue https://github.com/dotnet/diagnostics/issues/3726 Co-authored-by: Mike McLaughlin --- src/coreclr/vm/arm/stubs.cpp | 10 ++++++++++ src/coreclr/vm/arm64/stubs.cpp | 24 ++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/coreclr/vm/arm/stubs.cpp b/src/coreclr/vm/arm/stubs.cpp index 634eea810a31df..36eaeb51cdc5de 100644 --- a/src/coreclr/vm/arm/stubs.cpp +++ b/src/coreclr/vm/arm/stubs.cpp @@ -671,6 +671,16 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->pCurrentContext->R10 = (DWORD)(pUnwoundState->captureR4_R11[6]); pRD->pCurrentContext->R11 = (DWORD)(pUnwoundState->captureR4_R11[7]); + pRD->pCurrentContextPointers->R4 = &pRD->pCurrentContext->R4; + pRD->pCurrentContextPointers->R5 = &pRD->pCurrentContext->R5; + pRD->pCurrentContextPointers->R6 = &pRD->pCurrentContext->R6; + pRD->pCurrentContextPointers->R7 = &pRD->pCurrentContext->R7; + pRD->pCurrentContextPointers->R8 = &pRD->pCurrentContext->R8; + pRD->pCurrentContextPointers->R9 = &pRD->pCurrentContext->R9; + pRD->pCurrentContextPointers->R10 = &pRD->pCurrentContext->R10; + pRD->pCurrentContextPointers->R11 = &pRD->pCurrentContext->R11; + pRD->pCurrentContextPointers->Lr = &pRD->pCurrentContext->Lr; + return; } #endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index bc3e2b9609caeb..4ae26363fd2d24 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -472,18 +472,18 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->pCurrentContext->Fp = (DWORD64)(pUnwoundState->captureX19_X29[10]); pRD->pCurrentContext->Lr = NULL; // Unwind again to get Caller's PC - pRD->pCurrentContextPointers->X19 = pUnwoundState->ptrX19_X29[0]; - pRD->pCurrentContextPointers->X20 = pUnwoundState->ptrX19_X29[1]; - pRD->pCurrentContextPointers->X21 = pUnwoundState->ptrX19_X29[2]; - pRD->pCurrentContextPointers->X22 = pUnwoundState->ptrX19_X29[3]; - pRD->pCurrentContextPointers->X23 = pUnwoundState->ptrX19_X29[4]; - pRD->pCurrentContextPointers->X24 = pUnwoundState->ptrX19_X29[5]; - pRD->pCurrentContextPointers->X25 = pUnwoundState->ptrX19_X29[6]; - pRD->pCurrentContextPointers->X26 = pUnwoundState->ptrX19_X29[7]; - pRD->pCurrentContextPointers->X27 = pUnwoundState->ptrX19_X29[8]; - pRD->pCurrentContextPointers->X28 = pUnwoundState->ptrX19_X29[9]; - pRD->pCurrentContextPointers->Fp = pUnwoundState->ptrX19_X29[10]; - pRD->pCurrentContextPointers->Lr = NULL; + pRD->pCurrentContextPointers->X19 = &pRD->pCurrentContext->X19; + pRD->pCurrentContextPointers->X20 = &pRD->pCurrentContext->X20; + pRD->pCurrentContextPointers->X21 = &pRD->pCurrentContext->X21; + pRD->pCurrentContextPointers->X22 = &pRD->pCurrentContext->X22; + pRD->pCurrentContextPointers->X23 = &pRD->pCurrentContext->X23; + pRD->pCurrentContextPointers->X24 = &pRD->pCurrentContext->X24; + pRD->pCurrentContextPointers->X25 = &pRD->pCurrentContext->X25; + pRD->pCurrentContextPointers->X26 = &pRD->pCurrentContext->X26; + pRD->pCurrentContextPointers->X27 = &pRD->pCurrentContext->X27; + pRD->pCurrentContextPointers->X28 = &pRD->pCurrentContext->X28; + pRD->pCurrentContextPointers->Fp = &pRD->pCurrentContext->Fp; + pRD->pCurrentContextPointers->Lr = &pRD->pCurrentContext->Lr; return; } From c96e5abe28678cc9ebd08d071de534ec7ed8b283 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:14:48 -0700 Subject: [PATCH 020/345] [release/8.0-rc1] [mono] Fix InlineArray tests on android platforms (#90679) * Enable inline array tests * Run android jobs only * Add verbose logging * Revert runtime changes * Remove android-arm64 job * Rename common assembly and revert CI changes * Rename assembly name --------- Co-authored-by: Milos Kotlar --- .../Loader/classloader/InlineArray/InlineArrayInvalid.csproj | 2 +- .../Loader/classloader/InlineArray/InlineArrayValid.csproj | 2 +- .../{InvalidCSharp.il => InvalidCSharpInlineArray.il} | 2 +- .../{InvalidCSharp.ilproj => InvalidCSharpInlineArray.ilproj} | 2 +- src/tests/issues.targets | 3 --- 5 files changed, 4 insertions(+), 7 deletions(-) rename src/tests/Loader/classloader/InlineArray/{InvalidCSharp.il => InvalidCSharpInlineArray.il} (98%) rename src/tests/Loader/classloader/InlineArray/{InvalidCSharp.ilproj => InvalidCSharpInlineArray.ilproj} (73%) diff --git a/src/tests/Loader/classloader/InlineArray/InlineArrayInvalid.csproj b/src/tests/Loader/classloader/InlineArray/InlineArrayInvalid.csproj index c9c4d3b28342f2..2b17f8cac36a5b 100644 --- a/src/tests/Loader/classloader/InlineArray/InlineArrayInvalid.csproj +++ b/src/tests/Loader/classloader/InlineArray/InlineArrayInvalid.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/tests/Loader/classloader/InlineArray/InlineArrayValid.csproj b/src/tests/Loader/classloader/InlineArray/InlineArrayValid.csproj index 125a6c3f5432e3..2ed1ccb70a0bbc 100644 --- a/src/tests/Loader/classloader/InlineArray/InlineArrayValid.csproj +++ b/src/tests/Loader/classloader/InlineArray/InlineArrayValid.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/tests/Loader/classloader/InlineArray/InvalidCSharp.il b/src/tests/Loader/classloader/InlineArray/InvalidCSharpInlineArray.il similarity index 98% rename from src/tests/Loader/classloader/InlineArray/InvalidCSharp.il rename to src/tests/Loader/classloader/InlineArray/InvalidCSharpInlineArray.il index ff8d65c09be001..af16b27db42d62 100644 --- a/src/tests/Loader/classloader/InlineArray/InvalidCSharp.il +++ b/src/tests/Loader/classloader/InlineArray/InvalidCSharpInlineArray.il @@ -3,7 +3,7 @@ .assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) } -.assembly InvalidCSharp { } +.assembly InvalidCSharpInlineArray { } .class public explicit ansi sealed beforefieldinit Explicit extends [System.Runtime]System.ValueType diff --git a/src/tests/Loader/classloader/InlineArray/InvalidCSharp.ilproj b/src/tests/Loader/classloader/InlineArray/InvalidCSharpInlineArray.ilproj similarity index 73% rename from src/tests/Loader/classloader/InlineArray/InvalidCSharp.ilproj rename to src/tests/Loader/classloader/InlineArray/InvalidCSharpInlineArray.ilproj index d577c8f9c7a1a1..2a82d64591e9d5 100644 --- a/src/tests/Loader/classloader/InlineArray/InvalidCSharp.ilproj +++ b/src/tests/Loader/classloader/InlineArray/InvalidCSharpInlineArray.ilproj @@ -3,6 +3,6 @@ Library - + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 09e50e73c7dd39..87f8bbf2673dd3 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -3482,9 +3482,6 @@ https://github.com/dotnet/runtime/issues/67359 - - https://github.com/dotnet/runtime/issues/90398 - From 322c85c11a4b8b1fd8ebdc3def52b8172262bb72 Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Wed, 16 Aug 2023 13:20:51 -0700 Subject: [PATCH 021/345] [release/8.0-rc1] Bump package version for net7 to 7.0.11 (#90651) Co-authored-by: Steve Pfister Co-authored-by: Larry Ewing --- eng/Versions.props | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index ff21c1ee1f07dc..d75c6567090d01 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -7,12 +7,14 @@ 0 0 8.0.100 - 7.0.8 + 7.0.11 6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11)) rc 1 -$(PreReleaseVersionLabel).$(PreReleaseVersionIteration) $(SdkBandVersion)$(WorkloadVersionSuffix) + + false $(MajorVersion).$(MinorVersion).0.0 From a37d1382047f6b6e79f4e1a6476fd48589d432a9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:22:34 -0700 Subject: [PATCH 022/345] [mono] Add a --path command line argument as an alternative to MONO_PATH. (#90678) Can be specified multiple times. Co-authored-by: Zoltan Varga --- src/mono/mono/mini/driver.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/mono/mono/mini/driver.c b/src/mono/mono/mini/driver.c index c5f04a816a1fa8..a49820113d18ad 100644 --- a/src/mono/mono/mini/driver.c +++ b/src/mono/mono/mini/driver.c @@ -1617,6 +1617,7 @@ mini_usage (void) #endif " --handlers Install custom handlers, use --help-handlers for details.\n" " --aot-path=PATH List of additional directories to search for AOT images.\n" + " --path=DIR Add DIR to the list of directories to search for assemblies.\n" ); g_print ("\nOptions:\n"); @@ -2069,6 +2070,7 @@ mono_main (int argc, char* argv[]) char *aot_options = NULL; GPtrArray *agents = NULL; char *extra_bindings_config_file = NULL; + GList *paths = NULL; #ifdef MONO_JIT_INFO_TABLE_TEST int test_jit_info_table = FALSE; #endif @@ -2294,6 +2296,8 @@ mono_main (int argc, char* argv[]) g_free (tmp); split++; } + } else if (strncmp (argv [i], "--path=", 7) == 0) { + paths = g_list_append (paths, argv [i] + 7); } else if (strncmp (argv [i], "--compile-all=", 14) == 0) { action = DO_COMPILE; recompilation_times = atoi (argv [i] + 14); @@ -2503,6 +2507,16 @@ mono_main (int argc, char* argv[]) if (g_hasenv ("MONO_XDEBUG")) enable_debugging = TRUE; + if (paths) { + char **p = g_new0 (char *, g_list_length (paths) + 1); + int pindex = 0; + for (GList *l = paths; l; l = l->next) + p [pindex ++] = (char*)l->data; + g_list_free (paths); + + mono_set_assemblies_path_direct (p); + } + #ifdef MONO_CROSS_COMPILE if (!mono_compile_aot) { fprintf (stderr, "This mono runtime is compiled for cross-compiling. Only the --aot option is supported.\n"); From 1a13ecb5965ad8eed7aa145a4856813441314e52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:24:39 -0700 Subject: [PATCH 023/345] [release/8.0] Add doc for the new invoker classes (#90636) * Add doc new invoker classes * Fix cref typo * Misc errors * Remove arg reference in 0-arg ctor summary --------- Co-authored-by: Steve Harter --- .../System/Reflection/ConstructorInvoker.cs | 62 +++++++++++++++ .../src/System/Reflection/MethodInvoker.cs | 75 +++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs index 67fc0d31919759..7f3c1a227e3718 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs @@ -11,6 +11,17 @@ namespace System.Reflection { + /// + /// Invokes the method reflected by the provided . + /// + /// + /// Used for better performance than when compatibility with that method + /// is not necessary and when the caller can cache the ConstructorInvoker instance for additional invoke calls.
+ /// Unlike , the invoke methods do not look up default values for arguments when + /// is specified. In addition, the target constructor may be inlined for performance and not + /// appear in stack traces. + ///
+ /// public sealed partial class ConstructorInvoker { private InvokeFunc_ObjSpanArgs? _invokeFunc_ObjSpanArgs; @@ -24,6 +35,17 @@ public sealed partial class ConstructorInvoker private readonly RuntimeConstructorInfo _method; private readonly bool _needsByRefStrategy; + /// + /// Creates a new instance of ConstructorInvoker. + /// + /// + /// For performance, the resulting instance should be cached for additional calls. + /// + /// The constructor that will be invoked. + /// An instance of a ConstructorInvoker. + /// + /// The is not a runtime-based method. + /// public static ConstructorInvoker Create(ConstructorInfo constructor) { ArgumentNullException.ThrowIfNull(constructor, nameof(constructor)); @@ -46,6 +68,21 @@ private ConstructorInvoker(RuntimeConstructorInfo constructor, RuntimeType[] arg Initialize(argumentTypes, out _strategy, out _invokerArgFlags, out _needsByRefStrategy); } + /// + /// Invokes the constructor. + /// + /// + /// An instance of the class associated with the constructor. + /// + /// + /// The type that declares the method is an open generic type. + /// + /// + /// The correct number of arguments were not provided. + /// + /// + /// The calling convention or signature is not supported. + /// public object Invoke() { if (_argCount != 0) @@ -56,6 +93,14 @@ public object Invoke() return InvokeImpl(null, null, null, null); } + /// + /// Invokes the constructor using the specified parameters. + /// + /// + /// The first argument for the invoked method. + /// + /// The arguments do not match the signature of the invoked constructor. + /// public object Invoke(object? arg1) { if (_argCount != 1) @@ -66,6 +111,9 @@ public object Invoke(object? arg1) return InvokeImpl(arg1, null, null, null); } + /// + /// The first argument for the invoked method. + /// The second argument for the invoked method. public object Invoke(object? arg1, object? arg2) { if (_argCount != 2) @@ -76,6 +124,10 @@ public object Invoke(object? arg1, object? arg2) return InvokeImpl(arg1, arg2, null, null); } + /// + /// The first argument for the invoked method. + /// The second argument for the invoked method. + /// The third argument for the invoked method. public object Invoke(object? arg1, object? arg2, object? arg3) { if (_argCount !=3) @@ -86,6 +138,11 @@ public object Invoke(object? arg1, object? arg2, object? arg3) return InvokeImpl(arg1, arg2, arg3, null); } + /// + /// The first argument for the invoked method. + /// The second argument for the invoked method. + /// The third argument for the invoked method. + /// The fourth argument for the invoked method. public object Invoke(object? arg1, object? arg2, object? arg3, object? arg4) { if (_argCount != 4) @@ -137,6 +194,11 @@ private object InvokeImpl(object? arg1, object? arg2, object? arg3, object? arg4 return InvokeDirectByRef(arg1, arg2, arg3, arg4); } + /// + /// The arguments for the invoked constructor. + /// + /// The arguments do not match the signature of the invoked constructor. + /// public object Invoke(Span arguments) { int argLen = arguments.Length; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs index b5496c37c0cc84..66a35dbd39c74b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs @@ -12,6 +12,17 @@ namespace System.Reflection { + /// + /// Invokes the method reflected by the provided . + /// + /// + /// Used for better performance than when compatibility with that method + /// is not necessary and when the caller can cache the MethodInvoker instance for additional invoke calls.
+ /// Unlike , the invoke methods do not look up default values for arguments when + /// is specified. In addition, the target method may be inlined for performance and not + /// appear in stack traces. + ///
+ /// public sealed partial class MethodInvoker { private InvokeFunc_ObjSpanArgs? _invokeFunc_ObjSpanArgs; @@ -26,6 +37,17 @@ public sealed partial class MethodInvoker private readonly bool _needsByRefStrategy; private readonly bool _isStatic; + /// + /// Creates a new instance of MethodInvoker. + /// + /// + /// For performance, the resulting instance should be cached for additional calls. + /// + /// The method that will be invoked. + /// An instance of a MethodInvoker. + /// + /// The is not a runtime-based method. + /// public static MethodInvoker Create(MethodBase method) { ArgumentNullException.ThrowIfNull(method, nameof(method)); @@ -60,6 +82,32 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) Initialize(argumentTypes, out _strategy, out _invokerArgFlags, out _needsByRefStrategy); } + /// + /// Invokes the method using the specified parameters. + /// + /// + /// The object on which to invoke the method. If the method is static, this argument is ignored. + /// + /// + /// An object containing the return value of the invoked method, + /// or null if the invoked method does not have a return value. + /// + /// + /// The obj parameter is null and the method is not static. + /// + /// -or- + /// + /// The method is not declared or inherited by the class of obj. + /// + /// + /// The type that declares the method is an open generic type. + /// + /// + /// The correct number of arguments were not provided. + /// + /// + /// The calling convention or signature is not supported. + /// public object? Invoke(object? obj) { if (_argCount != 0) @@ -70,6 +118,12 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) return InvokeImpl(obj, null, null, null, null); } + /// + /// The object on which to invoke the method. If the method is static, this argument is ignored. + /// The first argument for the invoked method. + /// + /// The arguments do not match the signature of the invoked method. + /// public object? Invoke(object? obj, object? arg1) { if (_argCount != 1) @@ -80,6 +134,10 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) return InvokeImpl(obj, arg1, null, null, null); } + /// + /// The object on which to invoke the method. If the method is static, this argument is ignored. + /// The first argument for the invoked method. + /// The second argument for the invoked method. public object? Invoke(object? obj, object? arg1, object? arg2) { if (_argCount != 2) @@ -90,6 +148,11 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) return InvokeImpl(obj, arg1, arg2, null, null); } + /// + /// The object on which to invoke the method. If the method is static, this argument is ignored. + /// The first argument for the invoked method. + /// The second argument for the invoked method. + /// The third argument for the invoked method. public object? Invoke(object? obj, object? arg1, object? arg2, object? arg3) { if (_argCount != 3) @@ -100,6 +163,12 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) return InvokeImpl(obj, arg1, arg2, arg3, null); } + /// + /// The object on which to invoke the method. If the method is static, this argument is ignored. + /// The first argument for the invoked method. + /// The second argument for the invoked method. + /// The third argument for the invoked method. + /// The fourth argument for the invoked method. public object? Invoke(object? obj, object? arg1, object? arg2, object? arg3, object? arg4) { if (_argCount != 4) @@ -156,6 +225,12 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) return InvokeDirectByRef(obj, arg1, arg2, arg3, arg4); } + /// + /// The object on which to invoke the method. If the method is static, this argument is ignored. + /// The arguments for the invoked method. + /// + /// The arguments do not match the signature of the invoked method. + /// public object? Invoke(object? obj, Span arguments) { int argLen = arguments.Length; From 68213d01c2d49361c1a3aaba7cc935dd906b9fd5 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Wed, 16 Aug 2023 15:38:38 -0700 Subject: [PATCH 024/345] Do not set fetch depth on source-build (#90703) --- eng/pipelines/common/global-build-job.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml index 7e24fd3d045d5a..b870ba34757c21 100644 --- a/eng/pipelines/common/global-build-job.yml +++ b/eng/pipelines/common/global-build-job.yml @@ -147,7 +147,10 @@ jobs: steps: - checkout: self clean: true - fetchDepth: $(checkoutFetchDepth) + # If running in source build mode, a git stash will be used for the inner clone. Avoid setting a fetch depth, + # as a stash of a shallow cloned repo is not currently supported. + ${{ if ne(parameters.isSourceBuild, true) }}: + fetchDepth: $(checkoutFetchDepth) - ${{ if and(eq(parameters.isOfficialBuild, true), notin(parameters.osGroup, 'osx', 'maccatalyst', 'ios', 'iossimulator', 'tvos', 'tvossimulator')) }}: - template: /eng/pipelines/common/restore-internal-tools.yml From f84caca6fce726501f6722dab5f78db8bc0d88fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 15:39:04 -0700 Subject: [PATCH 025/345] Do not set fetch depth on source-build (#90704) Co-authored-by: Matt Mitchell --- eng/pipelines/common/global-build-job.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml index 7e24fd3d045d5a..b870ba34757c21 100644 --- a/eng/pipelines/common/global-build-job.yml +++ b/eng/pipelines/common/global-build-job.yml @@ -147,7 +147,10 @@ jobs: steps: - checkout: self clean: true - fetchDepth: $(checkoutFetchDepth) + # If running in source build mode, a git stash will be used for the inner clone. Avoid setting a fetch depth, + # as a stash of a shallow cloned repo is not currently supported. + ${{ if ne(parameters.isSourceBuild, true) }}: + fetchDepth: $(checkoutFetchDepth) - ${{ if and(eq(parameters.isOfficialBuild, true), notin(parameters.osGroup, 'osx', 'maccatalyst', 'ios', 'iossimulator', 'tvos', 'tvossimulator')) }}: - template: /eng/pipelines/common/restore-internal-tools.yml From b5a0345e44924bcbba2a29234d77c8f5b96c87ec Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:36:32 -0700 Subject: [PATCH 026/345] Update dependencies from https://github.com/dotnet/arcade build 20230815.4 (#90665) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23411.1 -> To Version 8.0.0-beta.23415.4 Dependency coherency updates Microsoft.DotNet.XliffTasks From Version 1.0.0-beta.23408.1 -> To Version 1.0.0-beta.23415.1 (parent: Microsoft.DotNet.Arcade.Sdk Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- eng/Version.Details.xml | 76 +++++++++++++------------- eng/Versions.props | 30 +++++----- eng/common/SetupNugetSources.ps1 | 8 +-- eng/common/SetupNugetSources.sh | 6 +- eng/common/native/init-distro-rid.sh | 6 +- eng/common/sdl/trim-assets-version.ps1 | 75 +++++++++++++++++++++++++ eng/common/tools.ps1 | 6 +- global.json | 6 +- 8 files changed, 145 insertions(+), 68 deletions(-) create mode 100644 eng/common/sdl/trim-assets-version.ps1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e31341152d13b0..6d255bdbc9f2af 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -107,79 +107,79 @@ - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/xliff-tasks - 493329204079519072f0241ed26f692bdee0d60c + 649a1e75101b701d753ee41efbe9038f9b23a0db - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d https://github.com/dotnet/runtime-assets @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 9b2af35a6702526dc8a7c5fcadcc44efd0dca170 + 46ff142f43e887d5f9a4d87ef39d72166f61db8d https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index d75c6567090d01..fd3e699e214032 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,21 +85,21 @@ 8.0.100-preview.7.23329.3 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 2.5.1-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 - 8.0.0-beta.23411.1 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 2.5.1-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 + 8.0.0-beta.23415.4 6.0.0-preview.1.102 diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1 index 2dc86ea2cdda1a..6c65e81925f2a3 100644 --- a/eng/common/SetupNugetSources.ps1 +++ b/eng/common/SetupNugetSources.ps1 @@ -2,7 +2,7 @@ # This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080 # # What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry -# under for each Maestro managed private feed. Two additional credential +# under for each Maestro managed private feed. Two additional credential # entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport. # # This script needs to be called in every job that will restore packages and which the base repo has @@ -37,7 +37,7 @@ Set-StrictMode -Version 2.0 # Add source entry to PackageSources function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $Password) { $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']") - + if ($packageSource -eq $null) { $packageSource = $doc.CreateElement("add") @@ -48,7 +48,7 @@ function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Usern else { Write-Host "Package source $SourceName already present." } - + AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $Password } @@ -89,7 +89,7 @@ function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $Passw $maestroPrivateSources = $Sources.SelectNodes("add[contains(@key,'darc-int')]") Write-Host "Inserting credentials for $($maestroPrivateSources.Count) Maestro's private feeds." - + ForEach ($PackageSource in $maestroPrivateSources) { Write-Host "`tInserting credential for Maestro's feed:" $PackageSource.Key AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -Password $Password diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh index a8bb8acd3be180..d387c7eac95e54 100644 --- a/eng/common/SetupNugetSources.sh +++ b/eng/common/SetupNugetSources.sh @@ -4,7 +4,7 @@ # This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080 # # What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry -# under for each Maestro's managed private feed. Two additional credential +# under for each Maestro's managed private feed. Two additional credential # entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport. # # This script needs to be called in every job that will restore packages and which the base repo has @@ -68,7 +68,7 @@ if [ "$?" != "0" ]; then sed -i.bak "s|$ConfigNodeHeader|$ConfigNodeHeader${NL}$PackageSourcesTemplate|" $ConfigFile fi -# Ensure there is a ... section. +# Ensure there is a ... section. grep -i "" $ConfigFile if [ "$?" != "0" ]; then echo "Adding ... section." @@ -142,7 +142,7 @@ IFS=$PrevIFS for FeedName in ${PackageSources[@]} ; do # Check if there is no existing credential for this FeedName - grep -i "<$FeedName>" $ConfigFile + grep -i "<$FeedName>" $ConfigFile if [ "$?" != "0" ]; then echo "Adding credentials for $FeedName." diff --git a/eng/common/native/init-distro-rid.sh b/eng/common/native/init-distro-rid.sh index aba9fe24028b0f..de1687b2ccbe79 100644 --- a/eng/common/native/init-distro-rid.sh +++ b/eng/common/native/init-distro-rid.sh @@ -79,7 +79,6 @@ getNonPortableDistroRid() # Input: # os: (str) # arch: (str) -# isPortable: (int) # rootfsDir?: (nullable:string) # # Return: @@ -97,10 +96,9 @@ initDistroRidGlobal() { local targetOs="$1" local targetArch="$2" - local isPortable="$3" local rootfsDir="" - if [ "$#" -ge 4 ]; then - rootfsDir="$4" + if [ "$#" -ge 3 ]; then + rootfsDir="$3" fi if [ -n "${rootfsDir}" ]; then diff --git a/eng/common/sdl/trim-assets-version.ps1 b/eng/common/sdl/trim-assets-version.ps1 new file mode 100644 index 00000000000000..d8cfec910c77e6 --- /dev/null +++ b/eng/common/sdl/trim-assets-version.ps1 @@ -0,0 +1,75 @@ +<# +.SYNOPSIS +Install and run the 'Microsoft.DotNet.VersionTools.Cli' tool with the 'trim-artifacts-version' command to trim the version from the NuGet assets file name. + +.PARAMETER InputPath +Full path to directory where artifact packages are stored + +.PARAMETER Recursive +Search for NuGet packages recursively + +#> + +Param( + [string] $InputPath, + [bool] $Recursive = $true +) + +$CliToolName = "Microsoft.DotNet.VersionTools.Cli" + +function Install-VersionTools-Cli { + param( + [Parameter(Mandatory=$true)][string]$Version + ) + + Write-Host "Installing the package '$CliToolName' with a version of '$version' ..." + $feed = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" + + $argumentList = @("tool", "install", "--local", "$CliToolName", "--add-source $feed", "--no-cache", "--version $Version") + Start-Process "$dotnet" -Verbose -ArgumentList $argumentList -NoNewWindow -Wait +} + +# ------------------------------------------------------------------- + +if (!(Test-Path $InputPath)) { + Write-Host "Input Path '$InputPath' does not exist" + ExitWithExitCode 1 +} + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 2.0 + +$disableConfigureToolsetImport = $true +$global:LASTEXITCODE = 0 + +# `tools.ps1` checks $ci to perform some actions. Since the SDL +# scripts don't necessarily execute in the same agent that run the +# build.ps1/sh script this variable isn't automatically set. +$ci = $true +. $PSScriptRoot\..\tools.ps1 + +try { + $dotnetRoot = InitializeDotNetCli -install:$true + $dotnet = "$dotnetRoot\dotnet.exe" + + $toolsetVersion = Read-ArcadeSdkVersion + Install-VersionTools-Cli -Version $toolsetVersion + + $cliToolFound = (& "$dotnet" tool list --local | Where-Object {$_.Split(' ')[0] -eq $CliToolName}) + if ($null -eq $cliToolFound) { + Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "The '$CliToolName' tool is not installed." + ExitWithExitCode 1 + } + + Exec-BlockVerbosely { + & "$dotnet" $CliToolName trim-assets-version ` + --assets-path $InputPath ` + --recursive $Recursive + Exit-IfNZEC "Sdl" + } +} +catch { + Write-Host $_ + Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ + ExitWithExitCode 1 +} \ No newline at end of file diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index c9eced9f7df4c6..aa74ab4a81e782 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -671,6 +671,10 @@ function InitializeNativeTools() { } } +function Read-ArcadeSdkVersion() { + return $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk' +} + function InitializeToolset() { if (Test-Path variable:global:_ToolsetBuildProj) { return $global:_ToolsetBuildProj @@ -678,7 +682,7 @@ function InitializeToolset() { $nugetCache = GetNuGetPackageCachePath - $toolsetVersion = $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk' + $toolsetVersion = Read-ArcadeSdkVersion $toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt" if (Test-Path $toolsetLocationFile) { diff --git a/global.json b/global.json index b4ca83d356c283..cf4ac698e3e8cb 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23411.1", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23411.1", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23411.1", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23415.4", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23415.4", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23415.4", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From a9b1d3c86611b0e49bedec766ebe1110e1ac1b9f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 09:25:09 -0600 Subject: [PATCH 027/345] Fix PortableRuntimeIdentifierGraph.json not found during runtime repo source build (#90714) Co-authored-by: Elinor Fung --- eng/liveBuilds.targets | 6 ------ 1 file changed, 6 deletions(-) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 118601229cf8b7..370e19805cc3a0 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -260,10 +260,4 @@ DependsOnTargets=" ResolveLibrariesRefAssembliesFromLocalBuild; ResolveLibrariesRuntimeFilesFromLocalBuild" /> - - - - $([MSBuild]::NormalizePath('$(ArtifactsBinDir)', 'Microsoft.NETCore.Platforms', 'runtime.json')) - $([MSBuild]::NormalizePath('$(LibrariesProjectRoot)', 'Microsoft.NETCore.Platforms', 'src', 'runtime.json')) - From 3924341ea7216d9b313d5d8e0590fbd3dca4be00 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 09:44:10 -0700 Subject: [PATCH 028/345] Release the stream once the response is sent (#90722) Co-authored-by: ManickaP --- .../Net/Http/Http3LoopbackConnection.cs | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs index ec5c7a022c65a6..9d6fef5fb3a720 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackConnection.cs @@ -108,11 +108,6 @@ public static int GetRequestId(QuicStream stream) return checked((int)stream.Id + 1); } - public Http3LoopbackStream GetOpenRequest(int requestId = 0) - { - return requestId == 0 ? _currentStream : _openStreams[requestId - 1]; - } - public override Task InitializeConnectionAsync() { throw new NotImplementedException(); @@ -195,6 +190,17 @@ public async Task EstablishControlStreamAsync(SettingsEntry[] settingsEntries) await _outboundControlStream.SendSettingsFrameAsync(settingsEntries); } + public async Task DisposeCurrentStream() + { + Assert.NotNull(_currentStream); + Assert.True(_currentStreamId >= 0); + + await _currentStream.DisposeAsync().ConfigureAwait(false); + _openStreams.Remove((int)_currentStreamId); + _currentStream = null; + _currentStreamId = -4; + } + public override async Task ReadRequestBodyAsync() { return await _currentStream.ReadRequestBodyAsync().ConfigureAwait(false); @@ -206,24 +212,32 @@ public override async Task ReadRequestDataAsync(bool readBody = return await stream.ReadRequestDataAsync(readBody).ConfigureAwait(false); } - public override Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null, string content = "", bool isFinal = true) + public override async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null, string content = "", bool isFinal = true) { - return GetOpenRequest().SendResponseAsync(statusCode, headers, content, isFinal); + await _currentStream.SendResponseAsync(statusCode, headers, content, isFinal); + if (isFinal) + { + await DisposeCurrentStream().ConfigureAwait(false); + } } - public override Task SendResponseBodyAsync(byte[] content, bool isFinal = true) + public override async Task SendResponseBodyAsync(byte[] content, bool isFinal = true) { - return GetOpenRequest().SendResponseBodyAsync(content, isFinal); + await _currentStream.SendResponseBodyAsync(content, isFinal); + if (isFinal) + { + await DisposeCurrentStream().ConfigureAwait(false); + } } public override Task SendResponseHeadersAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null) { - return GetOpenRequest().SendResponseHeadersAsync(statusCode, headers); + return _currentStream.SendResponseHeadersAsync(statusCode, headers); } public override Task SendPartialResponseHeadersAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null) { - return GetOpenRequest().SendPartialResponseHeadersAsync(statusCode, headers); + return _currentStream.SendPartialResponseHeadersAsync(statusCode, headers); } public override async Task HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList headers = null, string content = "") @@ -310,7 +324,7 @@ public async Task WaitForClientDisconnectAsync(bool refuseNewRequests = true) public override async Task WaitForCancellationAsync(bool ignoreIncomingData = true) { - await GetOpenRequest().WaitForCancellationAsync(ignoreIncomingData).ConfigureAwait(false); + await _currentStream.WaitForCancellationAsync(ignoreIncomingData).ConfigureAwait(false); } public override Task WaitForCloseAsync(CancellationToken cancellationToken) From e20cc4e3e4e90540659b78c8938aba3c2238fae7 Mon Sep 17 00:00:00 2001 From: Matt Mitchell Date: Thu, 17 Aug 2023 10:02:09 -0700 Subject: [PATCH 029/345] Call SetupNuGetSources for installer jobs (#90754) --- eng/pipelines/installer/jobs/build-job.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/eng/pipelines/installer/jobs/build-job.yml b/eng/pipelines/installer/jobs/build-job.yml index 5a0e37157e45c5..04be011a540758 100644 --- a/eng/pipelines/installer/jobs/build-job.yml +++ b/eng/pipelines/installer/jobs/build-job.yml @@ -296,6 +296,25 @@ jobs: - checkout: self clean: true fetchDepth: $(checkoutFetchDepth) + + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - ${{ if ne(parameters.osGroup, 'windows') }}: + - task: Bash@3 + displayName: Setup Private Feeds Credentials + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh + arguments: $(Build.SourcesDirectory)/NuGet.config $Token + env: + Token: $(dn-bot-dnceng-artifact-feeds-rw) + - ${{ else }}: + - task: PowerShell@2 + displayName: Setup Private Feeds Credentials + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1 + arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token + env: + Token: $(dn-bot-dnceng-artifact-feeds-rw) + - ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}: - template: /eng/pipelines/common/download-artifact-step.yml parameters: From 3ab4246e5a3913786dd846da5cbbfa96435a3243 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 10:27:20 -0700 Subject: [PATCH 030/345] [release/8.0] JIT: Disallow mismatched GC-ness for physical promotions (#90739) * JIT: Disallow mismatched GC-ness for physical promotions Physical promotion was working under the assumption that reinterpreting GC pointers is undefined behavior, and would happily promote GC pointers as integers if it saw such accesses. However, physical promotion is function wide while the UB accesses can be happening in a restricted (dynamically unreachable) scope. This exact situation happens in MemoryExtensions.Contains. The issue was uncovered under jit stress where we did not fold away the guard early enough, meaning that promotion then saw a `TYP_LONG` access of a `struct { object, int }` and proceeded to promote it as such. Fix #90602 * Address feedback --------- Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/layout.cpp | 34 ++++++++++++++++++++++++++++++++ src/coreclr/jit/layout.h | 2 ++ src/coreclr/jit/promotion.cpp | 37 ++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/layout.cpp b/src/coreclr/jit/layout.cpp index 113414ddfd7f7a..918fd4ab6521d4 100644 --- a/src/coreclr/jit/layout.cpp +++ b/src/coreclr/jit/layout.cpp @@ -421,6 +421,7 @@ void ClassLayout::InitializeGCPtrs(Compiler* compiler) // // Return value: // true if at least one GC ByRef, false otherwise. +// bool ClassLayout::HasGCByRef() const { unsigned slots = GetSlotCount(); @@ -435,6 +436,39 @@ bool ClassLayout::HasGCByRef() const return false; } +//------------------------------------------------------------------------ +// IntersectsGCPtr: check if the specified interval intersects with a GC +// pointer. +// +// Parameters: +// offset - The start offset of the interval +// size - The size of the interval +// +// Return value: +// True if it does. +// +bool ClassLayout::IntersectsGCPtr(unsigned offset, unsigned size) const +{ + if (!HasGCPtr()) + { + return false; + } + + unsigned startSlot = offset / TARGET_POINTER_SIZE; + unsigned endSlot = (offset + size - 1) / TARGET_POINTER_SIZE; + assert((startSlot < GetSlotCount()) && (endSlot < GetSlotCount())); + + for (unsigned i = startSlot; i <= endSlot; i++) + { + if (IsGCPtr(i)) + { + return true; + } + } + + return false; +} + //------------------------------------------------------------------------ // AreCompatible: check if 2 layouts are the same for copying. // diff --git a/src/coreclr/jit/layout.h b/src/coreclr/jit/layout.h index 0e9d6ed65d03d3..59ecaa9405485d 100644 --- a/src/coreclr/jit/layout.h +++ b/src/coreclr/jit/layout.h @@ -216,6 +216,8 @@ class ClassLayout } } + bool IntersectsGCPtr(unsigned offset, unsigned size) const; + static bool AreCompatible(const ClassLayout* layout1, const ClassLayout* layout2); private: diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index e2c4e797a3c9d8..5982ed79283355 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -621,6 +621,38 @@ class LocalUses bool EvaluateReplacement( Compiler* comp, unsigned lclNum, const Access& access, unsigned inducedCount, weight_t inducedCountWtd) { + // Verify that this replacement has proper GC ness compared to the + // layout. While reinterpreting GC fields to integers can be considered + // UB, there are scenarios where it can happen safely: + // + // * The user code could have guarded the access with a dynamic check + // that it doesn't contain a GC pointer, so that the access is actually + // in dead code. This happens e.g. in span functions in SPC. + // + // * For byrefs, reinterpreting as an integer could be ok in a + // restricted scope due to pinning. + // + // In theory we could allow these promotions in the restricted scope, + // but currently physical promotion works on a function-wide basis. + + LclVarDsc* lcl = comp->lvaGetDesc(lclNum); + ClassLayout* layout = lcl->GetLayout(); + if (layout->IntersectsGCPtr(access.Offset, genTypeSize(access.AccessType))) + { + if (((access.Offset % TARGET_POINTER_SIZE) != 0) || + (layout->GetGCPtrType(access.Offset / TARGET_POINTER_SIZE) != access.AccessType)) + { + return false; + } + } + else + { + if (varTypeIsGC(access.AccessType)) + { + return false; + } + } + unsigned countOverlappedCallArg = 0; unsigned countOverlappedStoredFromCall = 0; @@ -678,9 +710,8 @@ class LocalUses // Now look at the overlapping struct uses that promotion will make more expensive. - unsigned countReadBacks = 0; - weight_t countReadBacksWtd = 0; - LclVarDsc* lcl = comp->lvaGetDesc(lclNum); + unsigned countReadBacks = 0; + weight_t countReadBacksWtd = 0; // For parameters or OSR locals we always need one read back. if (lcl->lvIsParam || lcl->lvIsOSRLocal) { From 77884726ecf744ea5bb2037b7cb52f0ed1ed6bc5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 10:55:24 -0700 Subject: [PATCH 031/345] [wasm] Pin sdk version to 8.0.100-rc.1.23415.5 for workload testing (#90748) .. because `dotnet-install --channel 8.0` is returning 9.0-alpha sdks right now. Co-authored-by: Ankit Jain --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index fd3e699e214032..760c9e8b76e3f7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -206,7 +206,7 @@ 2.45.0 2.45.0 - + 8.0.100-rc.1.23415.5 1.1.2-beta1.23323.1 7.0.0-preview-20221010.1 From 38a117099c2bc6e32c9fb3eaec324450448128eb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:33:37 -0700 Subject: [PATCH 032/345] Expose TC_* vars (#90761) Co-authored-by: EgorBo --- src/coreclr/inc/clrconfigvalues.h | 5 +++-- src/coreclr/vm/eeconfig.cpp | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index ed61a56b976d26..7b356b07443999 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -574,9 +574,10 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_QuickJitForLoops, W("TC_QuickJitForLoops RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TC_QuickJitForLoops, W("TC_QuickJitForLoops"), 0, "When quick JIT is enabled, quick JIT may also be used for methods that contain loops.") #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TC_AggressiveTiering, W("TC_AggressiveTiering"), 0, "Transition through tiers aggressively.") +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TC_CallCountThreshold, W("TC_CallCountThreshold"), TC_CallCountThreshold, "Number of times a method must be called in tier 0 after which it is promoted to the next tier.") +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TC_CallCountingDelayMs, W("TC_CallCountingDelayMs"), TC_CallCountingDelayMs, "A perpetual delay in milliseconds that is applied to call counting in tier 0 and jitting at higher tiers, while there is startup-like activity.") + RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_BackgroundWorkerTimeoutMs, W("TC_BackgroundWorkerTimeoutMs"), TC_BackgroundWorkerTimeoutMs, "How long in milliseconds the background worker thread may remain idle before exiting.") -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountThreshold, W("TC_CallCountThreshold"), TC_CallCountThreshold, "Number of times a method must be called in tier 0 after which it is promoted to the next tier.") -RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCountingDelayMs, W("TC_CallCountingDelayMs"), TC_CallCountingDelayMs, "A perpetual delay in milliseconds that is applied to call counting in tier 0 and jitting at higher tiers, while there is startup-like activity.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_DelaySingleProcMultiplier, W("TC_DelaySingleProcMultiplier"), TC_DelaySingleProcMultiplier, "Multiplier for TC_CallCountingDelayMs that is applied on a single-processor machine or when the process is affinitized to a single processor.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_CallCounting, W("TC_CallCounting"), 1, "Enabled by default (only activates when TieredCompilation is also enabled). If disabled immediately backpatches prestub, and likely prevents any promotion to higher tiers") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TC_UseCallCountingStubs, W("TC_UseCallCountingStubs"), 1, "Uses call counting stubs for faster call counting.") diff --git a/src/coreclr/vm/eeconfig.cpp b/src/coreclr/vm/eeconfig.cpp index 417910eb183bc0..566a0c17ad4aa5 100644 --- a/src/coreclr/vm/eeconfig.cpp +++ b/src/coreclr/vm/eeconfig.cpp @@ -721,7 +721,8 @@ HRESULT EEConfig::sync() fTieredCompilation_CallCounting = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_CallCounting) != 0; DWORD tieredCompilation_ConfiguredCallCountThreshold = - CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_CallCountThreshold); + Configuration::GetKnobDWORDValue(W("System.Runtime.TC_CallCountThreshold"), CLRConfig::EXTERNAL_TC_CallCountThreshold); + if (tieredCompilation_ConfiguredCallCountThreshold == 0) { tieredCompilation_CallCountThreshold = 1; @@ -735,8 +736,9 @@ HRESULT EEConfig::sync() tieredCompilation_CallCountThreshold = (UINT16)tieredCompilation_ConfiguredCallCountThreshold; } - tieredCompilation_CallCountingDelayMs = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TC_CallCountingDelayMs); - + tieredCompilation_CallCountingDelayMs = + Configuration::GetKnobDWORDValue(W("System.Runtime.TC_CallCountingDelayMs"), CLRConfig::EXTERNAL_TC_CallCountingDelayMs); + bool hasSingleProcessor = GetCurrentProcessCpuCount() == 1; if (hasSingleProcessor) { From 64dc1fc29a27a7d7139f7619a102bbfdc6f37253 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:35:36 -0700 Subject: [PATCH 033/345] Call SetupNuGetSources for installer jobs (#90759) Co-authored-by: Matt Mitchell --- eng/pipelines/installer/jobs/build-job.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/eng/pipelines/installer/jobs/build-job.yml b/eng/pipelines/installer/jobs/build-job.yml index 5a0e37157e45c5..04be011a540758 100644 --- a/eng/pipelines/installer/jobs/build-job.yml +++ b/eng/pipelines/installer/jobs/build-job.yml @@ -296,6 +296,25 @@ jobs: - checkout: self clean: true fetchDepth: $(checkoutFetchDepth) + + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - ${{ if ne(parameters.osGroup, 'windows') }}: + - task: Bash@3 + displayName: Setup Private Feeds Credentials + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh + arguments: $(Build.SourcesDirectory)/NuGet.config $Token + env: + Token: $(dn-bot-dnceng-artifact-feeds-rw) + - ${{ else }}: + - task: PowerShell@2 + displayName: Setup Private Feeds Credentials + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1 + arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token + env: + Token: $(dn-bot-dnceng-artifact-feeds-rw) + - ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}: - template: /eng/pipelines/common/download-artifact-step.yml parameters: From 515e5d1b905a86d2adfe8775a9b1ca215c8e535d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:38:32 -0700 Subject: [PATCH 034/345] [release/8.0] Update Get/SetFieldValue to Account for EnC (#90623) * update Get/SetFieldValue * get the address of the instance * Update src/coreclr/vm/invokeutil.cpp --------- Co-authored-by: Mikelle Co-authored-by: Jan Kotas --- src/coreclr/vm/invokeutil.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/invokeutil.cpp b/src/coreclr/vm/invokeutil.cpp index c4ba804a4c493f..e6ed2103393e37 100644 --- a/src/coreclr/vm/invokeutil.cpp +++ b/src/coreclr/vm/invokeutil.cpp @@ -906,9 +906,13 @@ void InvokeUtil::SetValidField(CorElementType fldType, { void* pFieldData; if (pField->IsStatic()) + { pFieldData = pField->GetCurrentStaticAddress(); + } else - pFieldData = (*((BYTE**)target)) + pField->GetOffset() + sizeof(Object); + { + pFieldData = pField->GetInstanceAddress(*target); + } if (*valueObj == NULL) InitValueClass(pFieldData, pMT); @@ -1049,9 +1053,12 @@ OBJECTREF InvokeUtil::GetFieldValue(FieldDesc* pField, TypeHandle fieldType, OBJ GCPROTECT_BEGIN(obj); // calculate the offset to the field... if (pField->IsStatic()) + { p = pField->GetCurrentStaticAddress(); - else { - p = (*((BYTE**)target)) + pField->GetOffset() + sizeof(Object); + } + else + { + p = pField->GetInstanceAddress(*target); } GCPROTECT_END(); From a2953d7ac31164d605434ceec911210c9cf74493 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:43:10 -0700 Subject: [PATCH 035/345] [release/8.0] [JIT] ARM64 - Temporary fix for ldp/stp optimizations - with test fix (#90758) * Added regression test 85765 * Mark M4 as NoInlining * Check current and last ins format to determine whether to proceed with the optimized ldr/str pair * Additional test * Feedback * Fix test * Fixing test again... --------- Co-authored-by: TIHan --- src/coreclr/jit/emitarm64.cpp | 9 +++ .../JitBlue/Runtime_85765/Runtime_85765.cs | 63 +++++++++++++++++++ .../Runtime_85765/Runtime_85765.csproj | 9 +++ 3 files changed, 81 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.csproj diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index b4e81322e2a696..f01ad548d2ee04 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -16615,6 +16615,15 @@ emitter::RegisterOrder emitter::IsOptimizableLdrStrWithPair( emitAttr prevSize = emitLastIns->idOpSize(); ssize_t prevImm = emitGetInsSC(emitLastIns); + // If we have this format, the 'imm' and/or 'prevImm' are not scaled(encoded), + // therefore we cannot proceed. + // TODO: In this context, 'imm' and 'prevImm' are assumed to be scaled(encoded). + // They should never be scaled(encoded) until its about to be written to the buffer. + if (fmt == IF_LS_2C || lastInsFmt == IF_LS_2C) + { + return eRO_none; + } + // Signed, *raw* immediate value fits in 7 bits, so for LDP/ STP the raw value is from -64 to +63. // For LDR/ STR, there are 9 bits, so we need to limit the range explicitly in software. if ((imm < -64) || (imm > 63) || (prevImm < -64) || (prevImm > 63)) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.cs b/src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.cs new file mode 100644 index 00000000000000..89c22ae90dc821 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_85765 +{ + public struct S0 + { + public S0(bool f1): this() + { + } + } + + public struct S1 + { + public byte F0; + public bool F1; + public bool F2; + } + + [Fact] + public static void Test() + { + S1 vr2 = M4(); + vr2.F2 |= vr2.F1; + Assert.False(Consume(vr2.F2)); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static S1 M4() + { + S1 var1 = default(S1); + var vr0 = new S0(false); + return var1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool Consume(bool value) + { + return value; + } + + // ------ + + [Fact] + public unsafe static void Test2() + { + byte* bytes = stackalloc byte[1024]; + bytes[0x1A] = 1; + bytes[0x1B] = 2; + int sum = Foo(bytes); + Assert.True(sum == 515); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public unsafe static int Foo(byte* b) + { + return Unsafe.ReadUnaligned(ref b[0x1A]) + Unsafe.ReadUnaligned(ref b[0x1B]); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.csproj new file mode 100644 index 00000000000000..a4cc9d0594f93e --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_85765/Runtime_85765.csproj @@ -0,0 +1,9 @@ + + + True + True + + + + + From e64cdbb17b1023f30d1349badc4e045ded3a7a15 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:49:13 -0700 Subject: [PATCH 036/345] [release/8.0] Switch fx_ver_t::as_str from stringstream to append/to_string (#90760) * Switch fx_ver_t::as_str from stringstream to append/to_string * Switch version_t::as_str * Remove unnecessary include --------- Co-authored-by: Elinor Fung --- src/native/corehost/fxr/fx_ver.cpp | 31 ++++++-------------- src/native/corehost/fxr/fx_ver.h | 2 -- src/native/corehost/hostmisc/pal.unix.cpp | 1 - src/native/corehost/hostmisc/pal.windows.cpp | 1 - src/native/corehost/hostpolicy/version.cpp | 16 +++++----- 5 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/native/corehost/fxr/fx_ver.cpp b/src/native/corehost/fxr/fx_ver.cpp index 254f408effe9b8..7a857cdff473b0 100644 --- a/src/native/corehost/fxr/fx_ver.cpp +++ b/src/native/corehost/fxr/fx_ver.cpp @@ -70,31 +70,18 @@ bool fx_ver_t::operator >=(const fx_ver_t& b) const pal::string_t fx_ver_t::as_str() const { - pal::stringstream_t stream; - stream << m_major << _X(".") << m_minor << _X(".") << m_patch; + pal::string_t version = pal::to_string(m_major); + version += _X('.'); + version += pal::to_string(m_minor); + version += _X('.'); + version += pal::to_string(m_patch); if (!m_pre.empty()) - { - stream << m_pre; - } - if (!m_build.empty()) - { - stream << m_build; - } - return stream.str(); -} + version += m_pre; -pal::string_t fx_ver_t::prerelease_glob() const -{ - pal::stringstream_t stream; - stream << m_major << _X(".") << m_minor << _X(".") << m_patch << _X("-*"); - return stream.str(); -} + if (!m_build.empty()) + version += m_build; -pal::string_t fx_ver_t::patch_glob() const -{ - pal::stringstream_t stream; - stream << m_major << _X(".") << m_minor << _X(".*"); - return stream.str(); + return version; } static pal::string_t getId(const pal::string_t &ids, size_t idStart) diff --git a/src/native/corehost/fxr/fx_ver.h b/src/native/corehost/fxr/fx_ver.h index 5f5348386897b0..29f010876e04ae 100644 --- a/src/native/corehost/fxr/fx_ver.h +++ b/src/native/corehost/fxr/fx_ver.h @@ -26,8 +26,6 @@ struct fx_ver_t bool is_empty() const { return m_major == -1; } pal::string_t as_str() const; - pal::string_t prerelease_glob() const; - pal::string_t patch_glob() const; bool operator ==(const fx_ver_t& b) const; bool operator !=(const fx_ver_t& b) const; diff --git a/src/native/corehost/hostmisc/pal.unix.cpp b/src/native/corehost/hostmisc/pal.unix.cpp index 46ffaf951adfb9..34520aefd7365a 100644 --- a/src/native/corehost/hostmisc/pal.unix.cpp +++ b/src/native/corehost/hostmisc/pal.unix.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "config.h" #include diff --git a/src/native/corehost/hostmisc/pal.windows.cpp b/src/native/corehost/hostmisc/pal.windows.cpp index 98e4efbed72f07..b11610492d3214 100644 --- a/src/native/corehost/hostmisc/pal.windows.cpp +++ b/src/native/corehost/hostmisc/pal.windows.cpp @@ -7,7 +7,6 @@ #include "longfile.h" #include -#include #include #include diff --git a/src/native/corehost/hostpolicy/version.cpp b/src/native/corehost/hostpolicy/version.cpp index ea643605ac88f2..c08316fe4b5a87 100644 --- a/src/native/corehost/hostpolicy/version.cpp +++ b/src/native/corehost/hostpolicy/version.cpp @@ -51,29 +51,31 @@ bool version_t::operator >=(const version_t& b) const pal::string_t version_t::as_str() const { - pal::stringstream_t stream; - + pal::string_t version; if (m_major >= 0) { - stream << m_major; + version += pal::to_string(m_major); if (m_minor >= 0) { - stream << _X(".") << m_minor; + version += _X('.'); + version += pal::to_string(m_minor); if (m_build >= 0) { - stream << _X(".") << m_build; + version += _X('.'); + version += pal::to_string(m_build); if (m_revision >= 0) { - stream << _X(".") << m_revision; + version += _X('.'); + version += pal::to_string(m_revision); } } } } - return stream.str(); + return version; } /*static*/ int version_t::compare(const version_t&a, const version_t& b) From 702d02c87b1601a6ec5f6cd6fa008bc9bb1b8adc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:58:58 -0700 Subject: [PATCH 037/345] [release/8.0-rc1] Improve filtering of candidate binding invocations in config binder gen (#90746) * Improve filtering of candidate binding invocations in config binder gen * Address feedback * Address feedback: rename helper; further tighten constraint * Add follow-up TODO * Revert TypeSyntax clause to fix failing tests --------- Co-authored-by: Layomi Akinrinade --- .../ConfigurationBindingGenerator.Parser.cs | 10 +--- .../gen/ConfigurationBindingGenerator.cs | 8 +-- .../gen/Helpers/Parser/BinderInvocation.cs | 59 ++++++++----------- 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 758311958c4515..b0f53ef074078f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -7,7 +7,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Operations; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -44,13 +43,10 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm foreach (BinderInvocation invocation in _invocations) { - IInvocationOperation invocationOperation = invocation.Operation!; - if (!invocationOperation.TargetMethod.IsExtensionMethod) - { - continue; - } + IMethodSymbol targetMethod = invocation.Operation.TargetMethod; + INamedTypeSymbol? candidateBinderType = targetMethod.ContainingType; + Debug.Assert(targetMethod.IsExtensionMethod); - INamedTypeSymbol? candidateBinderType = invocationOperation.TargetMethod.ContainingType; if (SymbolEqualityComparer.Default.Equals(candidateBinderType, _typeSymbols.ConfigurationBinder)) { RegisterMethodInvocation_ConfigurationBinder(invocation); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs index 5d7a830c729542..70da582dddf0cd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs @@ -31,11 +31,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context) ? new CompilationData((CSharpCompilation)compilation) : null); - IncrementalValuesProvider inputCalls = context.SyntaxProvider + IncrementalValuesProvider inputCalls = context.SyntaxProvider .CreateSyntaxProvider( - (node, _) => node is InvocationExpressionSyntax invocation, + (node, _) => BinderInvocation.IsCandidateSyntaxNode(node), BinderInvocation.Create) - .Where(operation => operation is not null); + .Where(invocation => invocation is not null); IncrementalValueProvider<(CompilationData?, ImmutableArray)> inputData = compilationData.Combine(inputCalls.Collect()); @@ -59,7 +59,7 @@ private static void Execute(CompilationData compilationData, ImmutableArray IsCandidateMethodName_ConfigurationBinder(name) || @@ -52,23 +40,24 @@ static bool IsCandidateBindingMethodName(string name) => IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name); } - private static bool IsCandidateInvocation(IInvocationOperation operation) + private static bool IsBindingOperation(IInvocationOperation operation) { if (operation.TargetMethod is not IMethodSymbol { IsExtensionMethod: true, Name: string methodName, - ContainingType: ITypeSymbol + ContainingType: INamedTypeSymbol { Name: string containingTypeName, - ContainingNamespace: INamespaceSymbol { } containingNamespace, - } containingType - } method || - containingNamespace.ToDisplayString() is not string containingNamespaceName) + ContainingNamespace: INamespaceSymbol containingNamespace, + } + }) { return false; } + string containingNamespaceName = containingNamespace.ToDisplayString(); + return (containingTypeName) switch { "ConfigurationBinder" => From 149a289ddcdb0bb319e50ccf05010f02efc97049 Mon Sep 17 00:00:00 2001 From: mikelle-rogers <45022607+mikelle-rogers@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:00:36 -0700 Subject: [PATCH 038/345] Revert "Put HasNativeCodeReJITAware into GetFunctionAddress (#90049)" (#90696) This reverts commit eacb32e400b3f9d3522bed193bd534d02e8b170a. Need to investigate changes because they caused a test failure. --- src/coreclr/debug/daccess/dacimpl.h | 11 ++++++ src/coreclr/debug/daccess/task.cpp | 4 +- src/coreclr/debug/di/breakpoint.cpp | 2 - src/coreclr/debug/ee/controller.cpp | 24 ++++++++++-- src/coreclr/debug/ee/debugger.cpp | 56 +++++++++++++++++++++------ src/coreclr/debug/ee/debugger.h | 4 +- src/coreclr/debug/ee/functioninfo.cpp | 12 +++++- src/coreclr/debug/inc/dbgipcevents.h | 1 - src/coreclr/vm/dbginterface.h | 7 +++- src/coreclr/vm/eedbginterfaceimpl.cpp | 1 + src/coreclr/vm/encee.cpp | 4 +- src/coreclr/vm/method.cpp | 19 ++++----- src/coreclr/vm/method.hpp | 8 ++-- 13 files changed, 113 insertions(+), 40 deletions(-) diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index 8de684a5dae9a2..ddf61370f416e9 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1253,6 +1253,17 @@ class ClrDataAccess /* [out] */ union STUB_BUF* outBuffer, /* [out] */ ULONG32* outFlags); + DebuggerJitInfo* GetDebuggerJitInfo(MethodDesc* methodDesc, + TADDR addr) + { + if (g_pDebugger) + { + return g_pDebugger->GetJitInfo(methodDesc, (PBYTE)addr, NULL); + } + + return NULL; + } + HRESULT GetMethodExtents(MethodDesc* methodDesc, METH_EXTENTS** extents); HRESULT GetMethodVarInfo(MethodDesc* methodDesc, diff --git a/src/coreclr/debug/daccess/task.cpp b/src/coreclr/debug/daccess/task.cpp index ddbf251b7b9825..9e428e81adef2b 100644 --- a/src/coreclr/debug/daccess/task.cpp +++ b/src/coreclr/debug/daccess/task.cpp @@ -5225,7 +5225,7 @@ EnumMethodInstances::Next(ClrDataAccess* dac, } } - if (!m_methodIter.Current()->HasNativeCodeAnyVersion()) + if (!m_methodIter.Current()->HasNativeCodeReJITAware()) { goto NextMethod; } @@ -5243,7 +5243,7 @@ EnumMethodInstances::CdStart(MethodDesc* methodDesc, CLRDATA_ENUM* handle) { if (!methodDesc->HasClassOrMethodInstantiation() && - !(methodDesc->HasNativeCodeAnyVersion())) + !methodDesc->HasNativeCodeReJITAware()) { *handle = 0; return S_FALSE; diff --git a/src/coreclr/debug/di/breakpoint.cpp b/src/coreclr/debug/di/breakpoint.cpp index 568d7fc9fc66ad..ad45df5c618ace 100644 --- a/src/coreclr/debug/di/breakpoint.cpp +++ b/src/coreclr/debug/di/breakpoint.cpp @@ -211,13 +211,11 @@ HRESULT CordbFunctionBreakpoint::Activate(BOOL fActivate) if (codeIsIL) { pEvent->BreakpointData.nativeCodeMethodDescToken = pEvent->BreakpointData.nativeCodeMethodDescToken.NullPtr(); - pEvent->BreakpointData.codeStartAddress = 0; } else { pEvent->BreakpointData.nativeCodeMethodDescToken = (m_code.GetValue()->AsNativeCode())->GetVMNativeCodeMethodDescToken().ToLsPtr(); - pEvent->BreakpointData.codeStartAddress = (m_code.GetValue()->AsNativeCode())->GetAddress(); } // Note: we're sending a two-way event, so it blocks here diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 58e63ab399db2c..7dd186b4113d44 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -1247,8 +1247,26 @@ bool DebuggerController::BindPatch(DebuggerControllerPatch *patch, startAddr = (CORDB_ADDRESS_TYPE *) CORDB_ADDRESS_TO_PTR(patch->GetDJI()->m_addrOfCode); _ASSERTE(startAddr != NULL); } - //We should never be calling this function with both a NULL startAddr and a DJI that doesn't have code. - _ASSERTE(startAddr != NULL); + if (startAddr == NULL) + { + // Should not be trying to place patches on MethodDecs's for stubs. + // These stubs will never get jitted. + CONSISTENCY_CHECK_MSGF(!pMD->IsWrapperStub(), ("Can't place patch at stub md %p, %s::%s", + pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName)); + + startAddr = (CORDB_ADDRESS_TYPE *)g_pEEInterface->GetFunctionAddress(pMD); + // + // Code is not available yet to patch. The prestub should + // notify us when it is executed. + // + if (startAddr == NULL) + { + LOG((LF_CORDB, LL_INFO10000, + "DC::BP: Patch at 0x%zx not bindable yet.\n", patch->offset)); + + return false; + } + } } _ASSERTE(!g_pEEInterface->IsStub((const BYTE *)startAddr)); @@ -8638,7 +8656,7 @@ bool DebuggerFuncEvalComplete::SendEvent(Thread *thread, bool fIpChanged) // DebuggerEnCBreakpoint constructor - creates and activates a new EnC breakpoint // // Arguments: -// offset - IL offset in the function to place the patch +// offset - native offset in the function to place the patch // jitInfo - identifies the function in which the breakpoint is being placed // fTriggerType - breakpoint type: either REMAP_PENDING or REMAP_COMPLETE // pAppDomain - the breakpoint applies to the specified AppDomain only diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index d58a987244a8ea..a44a9e235f36cd 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -2841,8 +2841,6 @@ HRESULT Debugger::GetILToNativeMapping(PCODE pNativeCodeStartAddress, ULONG32 cM } CONTRACTL_END; - _ASSERTE(pNativeCodeStartAddress != NULL); - #ifdef PROFILING_SUPPORTED // At this point, we're pulling in the debugger. if (!HasLazyData()) @@ -3009,7 +3007,6 @@ HRESULT Debugger::GetILToNativeMappingIntoArrays( _ASSERTE(pcMap != NULL); _ASSERTE(prguiILOffset != NULL); _ASSERTE(prguiNativeOffset != NULL); - _ASSERTE(pNativeCodeStartAddress != NULL); // Any caller of GetILToNativeMappingIntoArrays had better call // InitializeLazyDataIfNecessary first! @@ -5414,6 +5411,28 @@ void Debugger::ReleaseAllRuntimeThreads(AppDomain *pAppDomain) g_pEEInterface->ResumeFromDebug(pAppDomain); } +// Given a method, get's its EnC version number. 1 if the method is not EnCed. +// Note that MethodDescs are reused between versions so this will give us +// the most recent EnC number. +int Debugger::GetMethodEncNumber(MethodDesc * pMethod) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + } + CONTRACTL_END; + + DebuggerJitInfo * dji = GetLatestJitInfoFromMethodDesc(pMethod); + if (dji == NULL) + { + // If there's no DJI, couldn't have been EnCed. + return 1; + } + return (int) dji->m_encVersion; +} + + bool Debugger::IsJMCMethod(Module* pModule, mdMethodDef tkMethod) { CONTRACTL @@ -6200,6 +6219,25 @@ void Debugger::LockAndSendEnCRemapCompleteEvent(MethodDesc *pMD) Thread *thread = g_pEEInterface->GetThread(); // Note that the debugger lock is reentrant, so we may or may not hold it already. SENDIPCEVENT_BEGIN(this, thread); + + EX_TRY + { + // Ensure the DJI for the latest version of this method has been pre-created. + // It's not clear whether this is necessary or not, but it shouldn't hurt since + // we're going to need to create it anyway since we'll be debugging inside it. + DebuggerJitInfo *dji = g_pDebugger->GetLatestJitInfoFromMethodDesc(pMD); + (void)dji; //prevent "unused variable" error from GCC + _ASSERTE( dji != NULL ); + } + EX_CATCH + { + // GetLatestJitInfo could throw on OOM, but the debugger isn't resiliant to OOM. + // I'm not aware of any other legitimate reason why it may throw, so we'll ASSERT + // if it fails. + _ASSERTE(!"Unexpected exception from Debugger::GetLatestJitInfoFromMethodDesc on EnC remap complete"); + } + EX_END_CATCH(RethrowTerminalExceptions); + // Send an EnC remap complete event to the Right Side. DebuggerIPCEvent* ipce = m_pRCThread->GetIPCEventSendBuffer(); InitIPCEvent(ipce, @@ -7827,7 +7865,6 @@ void Debugger::FirstChanceManagedExceptionCatcherFound(Thread *pThread, // Implements DebugInterface // Call by EE/exception. Must be on managed thread _ASSERTE(GetThreadNULLOk() != NULL); - _ASSERTE(pMethodAddr != NULL); // Quick check. if (!CORDebuggerAttached()) @@ -10461,7 +10498,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) DebuggerJitInfo * pDJI = NULL; if ((pMethodDesc != NULL) && (pDMI != NULL)) { - pDJI = pDMI->FindOrCreateInitAndAddJitInfo(pMethodDesc, PINSTRToPCODE(dac_cast(pEvent->BreakpointData.codeStartAddress))); + pDJI = pDMI->FindOrCreateInitAndAddJitInfo(pMethodDesc, NULL /* startAddr */); } { @@ -12588,7 +12625,7 @@ DWORD Debugger::GetThreadIdHelper(Thread *pThread) // does not own the memory provided via vars outparameter. //----------------------------------------------------------------------------- void Debugger::GetVarInfo(MethodDesc * fd, // [IN] method of interest - CORDB_ADDRESS nativeCodeAddress, // [IN] which edit version + void *DebuggerVersionToken, // [IN] which edit version SIZE_T * cVars, // [OUT] size of 'vars' const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored ) @@ -12600,7 +12637,7 @@ void Debugger::GetVarInfo(MethodDesc * fd, // [IN] method of interest } CONTRACTL_END; - DebuggerJitInfo * ji = g_pDebugger->GetJitInfo(fd, (const BYTE *)nativeCodeAddress); + DebuggerJitInfo * ji = (DebuggerJitInfo *)DebuggerVersionToken; // If we didn't supply a DJI, then we're asking for the most recent version. if (ji == NULL) @@ -12924,11 +12961,6 @@ HRESULT Debugger::UpdateFunction(MethodDesc* pMD, SIZE_T encVersion) // For each offset in the IL->Native map, set a new EnC breakpoint on the // ones that we know could be remap points. - - // Depending on which DJI was picked, the code might compute different IL offsets. The JIT may not guarantee it produces - // the same set of sequence points for every generic instantiation. - // Inside ENCSequencePointHelper there is logic that skips IL offsets that map to the same native offset. - // Its possible that one version of the code maps two IL offsets to the same native offset but another version of the code maps them to different offsets. PTR_DebuggerILToNativeMap seqMap = pJitInfo->GetSequenceMap(); for (unsigned int i = 0; i < pJitInfo->GetSequenceMapCount(); i++) { diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index 2c2440ddaf6977..26edd26a96140b 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -1933,6 +1933,8 @@ class Debugger : public DebugInterface bool IsJMCMethod(Module* pModule, mdMethodDef tkMethod); + int GetMethodEncNumber(MethodDesc * pMethod); + bool FirstChanceManagedException(Thread *pThread, SIZE_T currentIP, SIZE_T currentSP); @@ -1978,7 +1980,7 @@ class Debugger : public DebugInterface #endif // EnC_SUPPORTED void GetVarInfo(MethodDesc * fd, // [IN] method of interest - CORDB_ADDRESS nativeCodeAddress, // [IN] which edit version + void *DebuggerVersionToken, // [IN] which edit version SIZE_T * cVars, // [OUT] size of 'vars' const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored ); diff --git a/src/coreclr/debug/ee/functioninfo.cpp b/src/coreclr/debug/ee/functioninfo.cpp index 19910c6429a9c6..76d4be3ab232f2 100644 --- a/src/coreclr/debug/ee/functioninfo.cpp +++ b/src/coreclr/debug/ee/functioninfo.cpp @@ -1565,7 +1565,9 @@ DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* f GC_NOTRIGGER; } CONTRACTL_END; + _ASSERTE(fd != NULL); + // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata. if (fd->IsDynamicMethod()) { @@ -1574,8 +1576,16 @@ DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* f if (startAddr == NULL) { + // This will grab the start address for the current code version. startAddr = g_pEEInterface->GetFunctionAddress(fd); - _ASSERTE(startAddr != NULL); + if (startAddr == NULL) + { + startAddr = fd->GetNativeCodeReJITAware(); + if (startAddr == NULL) + { + return NULL; + } + } } else { diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h index e9643e50f480a2..9fe1afd31a54ba 100644 --- a/src/coreclr/debug/inc/dbgipcevents.h +++ b/src/coreclr/debug/inc/dbgipcevents.h @@ -2011,7 +2011,6 @@ struct MSLAYOUT DebuggerIPCEvent SIZE_T offset; SIZE_T encVersion; LSPTR_METHODDESC nativeCodeMethodDescToken; // points to the MethodDesc if !isIL - CORDB_ADDRESS codeStartAddress; } BreakpointData; struct MSLAYOUT diff --git a/src/coreclr/vm/dbginterface.h b/src/coreclr/vm/dbginterface.h index 85b9785bccbb9b..daa57d25c86cf3 100644 --- a/src/coreclr/vm/dbginterface.h +++ b/src/coreclr/vm/dbginterface.h @@ -203,7 +203,7 @@ class DebugInterface // Get debugger variable information for a specific version of a method virtual void GetVarInfo(MethodDesc * fd, // [IN] method of interest - CORDB_ADDRESS nativeCodeAddress, // [IN] which edit version + void *DebuggerVersionToken, // [IN] which edit version SIZE_T * cVars, // [OUT] size of 'vars' const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored ) = 0; @@ -262,6 +262,11 @@ class DebugInterface virtual bool IsJMCMethod(Module* pModule, mdMethodDef tkMethod) = 0; + // Given a method, get's its EnC version number. 1 if the method is not EnCed. + // Note that MethodDescs are reused between versions so this will give us + // the most recent EnC number. + virtual int GetMethodEncNumber(MethodDesc * pMethod) = 0; + virtual void SendLogSwitchSetting (int iLevel, int iReason, _In_z_ LPCWSTR pLogSwitchName, diff --git a/src/coreclr/vm/eedbginterfaceimpl.cpp b/src/coreclr/vm/eedbginterfaceimpl.cpp index 352a534d5c1a88..792c608918a61d 100644 --- a/src/coreclr/vm/eedbginterfaceimpl.cpp +++ b/src/coreclr/vm/eedbginterfaceimpl.cpp @@ -630,6 +630,7 @@ PCODE EEDbgInterfaceImpl::GetFunctionAddress(MethodDesc *pFD) SUPPORTS_DAC; } CONTRACTL_END; + return pFD->GetNativeCode(); } diff --git a/src/coreclr/vm/encee.cpp b/src/coreclr/vm/encee.cpp index 3339462ad7fe77..1dcfb8bf091f4c 100644 --- a/src/coreclr/vm/encee.cpp +++ b/src/coreclr/vm/encee.cpp @@ -806,8 +806,8 @@ NOINLINE void EditAndContinueModule::FixContextAndResume( // Get the var info which the codemanager will use for updating // enregistered variables correctly, or variables whose lifetimes differ // at the update point - g_pDebugInterface->GetVarInfo(pMD, oldCodeInfo.GetCodeAddress(), &oldVarInfoCount, &pOldVarInfo); - g_pDebugInterface->GetVarInfo(pMD, newCodeInfo.GetCodeAddress(), &newVarInfoCount, &pNewVarInfo); + g_pDebugInterface->GetVarInfo(pMD, oldDebuggerFuncHandle, &oldVarInfoCount, &pOldVarInfo); + g_pDebugInterface->GetVarInfo(pMD, NULL, &newVarInfoCount, &pNewVarInfo); #ifdef TARGET_X86 // save the frame pointer as FixContextForEnC might step on it. diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 29910d6cb4c1c3..62b24e3dc091c6 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -913,6 +913,7 @@ PCODE MethodDesc::GetNativeCode() WRAPPER_NO_CONTRACT; SUPPORTS_DAC; _ASSERTE(!IsDefaultInterfaceMethod() || HasNativeCodeSlot()); + if (HasNativeCodeSlot()) { // When profiler is enabled, profiler may ask to rejit a code even though we @@ -934,7 +935,7 @@ PCODE MethodDesc::GetNativeCode() return GetStableEntryPoint(); } -PCODE MethodDesc::GetNativeCodeAnyVersion() +PCODE MethodDesc::GetNativeCodeReJITAware() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; @@ -945,23 +946,19 @@ PCODE MethodDesc::GetNativeCodeAnyVersion() return pDefaultCode; } - else { CodeVersionManager *pCodeVersionManager = GetCodeVersionManager(); CodeVersionManager::LockHolder codeVersioningLockHolder; - ILCodeVersionCollection ilVersionCollection = pCodeVersionManager->GetILCodeVersions(PTR_MethodDesc(this)); - for (ILCodeVersionIterator curIL = ilVersionCollection.Begin(), endIL = ilVersionCollection.End(); curIL != endIL; curIL++) + ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(PTR_MethodDesc(this)); + if (!ilVersion.IsDefaultVersion()) { - NativeCodeVersionCollection nativeCollection = curIL->GetNativeCodeVersions(PTR_MethodDesc(this)); - for (NativeCodeVersionIterator curNative = nativeCollection.Begin(), endNative = nativeCollection.End(); curNative != endNative; curNative++) + NativeCodeVersion activeNativeCodeVersion = ilVersion.GetActiveNativeCodeVersion(PTR_MethodDesc(this)); + if (!activeNativeCodeVersion.IsNull()) { - PCODE native = curNative->GetNativeCode(); - if(native != NULL) - { - return native; - } + return activeNativeCodeVersion.GetNativeCode(); } } + return NULL; } } diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index aaecfb20779f34..4b34045b57671e 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1373,11 +1373,11 @@ class MethodDesc } // Perf warning: takes the CodeVersionManagerLock on every call - BOOL HasNativeCodeAnyVersion() + BOOL HasNativeCodeReJITAware() { LIMITED_METHOD_DAC_CONTRACT; - return GetNativeCodeAnyVersion() != NULL; + return GetNativeCodeReJITAware() != NULL; } BOOL SetNativeCodeInterlocked(PCODE addr, PCODE pExpected = NULL); @@ -1437,9 +1437,9 @@ class MethodDesc PCODE GetNativeCode(); // Returns GetNativeCode() if it exists, but also checks to see if there - // is a non-default code version that is populated with a code body and returns that. + // is a non-default IL code version and returns that. // Perf warning: takes the CodeVersionManagerLock on every call - PCODE GetNativeCodeAnyVersion(); + PCODE GetNativeCodeReJITAware(); #if defined(FEATURE_JIT_PITCHING) bool IsPitchable(); From f7df78f4c9b3944d1b937b264601d7b5da55f3ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Aug 2023 16:02:08 -0700 Subject: [PATCH 039/345] [release/8.0] Limit language version on Logger and Options source gens (#90709) * Limit language version on Logger and Options source gens * Exclude test in browser * Address the feedback * Fix Json test and apply more feedback * Remove quotes from language versions in source gen diagnostics. (#90720) --------- Co-authored-by: Tarek Mahmoud Sayed Co-authored-by: Eirik Tsarpalis --- docs/project/list-of-diagnostics.md | 10 +-- .../gen/DiagnosticDescriptors.cs | 8 +++ .../gen/LoggerMessageGenerator.Parser.cs | 7 ++ .../gen/Resources/Strings.resx | 6 ++ .../gen/Resources/xlf/Strings.cs.xlf | 10 +++ .../gen/Resources/xlf/Strings.de.xlf | 10 +++ .../gen/Resources/xlf/Strings.es.xlf | 10 +++ .../gen/Resources/xlf/Strings.fr.xlf | 10 +++ .../gen/Resources/xlf/Strings.it.xlf | 10 +++ .../gen/Resources/xlf/Strings.ja.xlf | 10 +++ .../gen/Resources/xlf/Strings.ko.xlf | 10 +++ .../gen/Resources/xlf/Strings.pl.xlf | 10 +++ .../gen/Resources/xlf/Strings.pt-BR.xlf | 10 +++ .../gen/Resources/xlf/Strings.ru.xlf | 10 +++ .../gen/Resources/xlf/Strings.tr.xlf | 10 +++ .../gen/Resources/xlf/Strings.zh-Hans.xlf | 10 +++ .../gen/Resources/xlf/Strings.zh-Hant.xlf | 10 +++ .../LoggerMessageGeneratorParserTests.cs | 54 +++++++++++++- .../gen/DiagDescriptors.cs | 7 ++ .../gen/Parser.cs | 7 ++ .../gen/Resources/Strings.resx | 6 ++ .../gen/Resources/xlf/Strings.cs.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.de.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.es.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.fr.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.it.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.ja.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.ko.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.pl.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.pt-BR.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.ru.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.tr.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 70 +++++++++++-------- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 70 +++++++++++-------- .../tests/SourceGeneration.Unit.Tests/Main.cs | 57 +++++++++++++++ .../Resources/Strings.resx | 6 ++ .../Resources/Strings.resx | 6 ++ .../gen/Resources/Strings.resx | 56 +++++++-------- .../gen/Resources/xlf/Strings.cs.xlf | 4 +- .../gen/Resources/xlf/Strings.de.xlf | 4 +- .../gen/Resources/xlf/Strings.es.xlf | 4 +- .../gen/Resources/xlf/Strings.fr.xlf | 4 +- .../gen/Resources/xlf/Strings.it.xlf | 4 +- .../gen/Resources/xlf/Strings.ja.xlf | 4 +- .../gen/Resources/xlf/Strings.ko.xlf | 4 +- .../gen/Resources/xlf/Strings.pl.xlf | 4 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 4 +- .../gen/Resources/xlf/Strings.ru.xlf | 4 +- .../gen/Resources/xlf/Strings.tr.xlf | 4 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 4 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 4 +- .../JsonSourceGeneratorDiagnosticsTests.cs | 8 +-- 52 files changed, 876 insertions(+), 454 deletions(-) diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 4f78e9e711653d..75d252218f8392 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -142,10 +142,10 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1023`__ | Generating more than 6 arguments is not supported | | __`SYSLIB1024`__ | Argument is using the unsupported out parameter modifier | | __`SYSLIB1025`__ | Multiple logging methods cannot use the same event name within a class | -| __`SYSLIB1026`__ | _`SYSLIB1026`-`SYSLIB1029` reserved for logging._ | -| __`SYSLIB1027`__ | _`SYSLIB1026`-`SYSLIB1029` reserved for logging._ | -| __`SYSLIB1028`__ | _`SYSLIB1026`-`SYSLIB1029` reserved for logging._ | -| __`SYSLIB1029`__ | _`SYSLIB1026`-`SYSLIB1029` reserved for logging._ | +| __`SYSLIB1026`__ | C# language version not supported by the logging source generator. | +| __`SYSLIB1027`__ | _`SYSLIB1001`-`SYSLIB1029` reserved for logging._ | +| __`SYSLIB1028`__ | _`SYSLIB1001`-`SYSLIB1029` reserved for logging._ | +| __`SYSLIB1029`__ | _`SYSLIB1001`-`SYSLIB1029` reserved for logging._ | | __`SYSLIB1030`__ | JsonSourceGenerator did not generate serialization metadata for type | | __`SYSLIB1031`__ | JsonSourceGenerator encountered a duplicate JsonTypeInfo property name | | __`SYSLIB1032`__ | JsonSourceGenerator encountered a context class that is not partial | @@ -250,7 +250,7 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1213`__ | Options validation generator: Member potentially missing enumerable validation. | | __`SYSLIB1214`__ | Options validation generator: Can't validate constants, static fields or properties. | | __`SYSLIB1215`__ | Options validation generator: Validation attribute on the member is inaccessible from the validator type. | -| __`SYSLIB1216`__ | *_`SYSLIB1201`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration.* | +| __`SYSLIB1216`__ | C# language version not supported by the options validation source generator. | | __`SYSLIB1217`__ | *_`SYSLIB1201`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration.* | | __`SYSLIB1218`__ | *_`SYSLIB1201`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration.* | | __`SYSLIB1219`__ | *_`SYSLIB1201`-`SYSLIB1219` reserved for Microsoft.Extensions.Options.SourceGeneration.* | diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs index ed51ed6164188d..ec89ae4a42bc9a 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/DiagnosticDescriptors.cs @@ -200,5 +200,13 @@ public static class DiagnosticDescriptors category: "LoggingGenerator", DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public static DiagnosticDescriptor LoggingUnsupportedLanguageVersion { get; } = new DiagnosticDescriptor( + id: "SYSLIB1026", + title: new LocalizableResourceString(nameof(SR.LoggingUnsupportedLanguageVersionTitle), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), + messageFormat: new LocalizableResourceString(nameof(SR.LoggingUnsupportedLanguageVersionMessageFormat), SR.ResourceManager, typeof(FxResources.Microsoft.Extensions.Logging.Generators.SR)), + category: "LoggingGenerator", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs index 2b5b8ca6a1a498..038b71bef0759b 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs @@ -591,6 +591,13 @@ static bool IsAllowedKind(SyntaxKind kind) => } } + if (results.Count > 0 && _compilation is CSharpCompilation { LanguageVersion : LanguageVersion version and < LanguageVersion.CSharp8 }) + { + // we only support C# 8.0 and above + Diag(DiagnosticDescriptors.LoggingUnsupportedLanguageVersion, null, version.ToDisplayString(), LanguageVersion.CSharp8.ToDisplayString()); + return Array.Empty(); + } + return results; } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx index 529263fda731fb..602e6f4730d216 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/Strings.resx @@ -231,4 +231,10 @@ Logging method contains malformed format strings + + C# language version not supported by the source generator. + + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf index ac5ddc07ceb05f..00e8b1cc7d91a1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf @@ -67,6 +67,16 @@ Metody protokolování musí být statické. + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings Metoda protokolování {0} obsahuje řetězce s poškozeným formátem. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf index c57008e516a5be..2e962cd97ac902 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf @@ -67,6 +67,16 @@ Protokollierungsmethoden müssen statisch sein. + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings Die Protokollierungsmethode „{0}“ enthält nicht wohlgeformte Formatzeichenfolgen. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf index 29cce5c24f3f77..46073f102868a1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf @@ -67,6 +67,16 @@ Los métodos de registro deben ser estáticos + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings El método de registro “{0}” contiene cadenas con formato incorrecto diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf index afd2c184fc42fa..2497ea11a88a04 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf @@ -67,6 +67,16 @@ Les méthodes de journalisation doivent être statiques + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings La méthode de journalisation « {0} »contient des chaînes de format incorrectes diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf index 99b2e817511ae8..06dadffd497939 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf @@ -67,6 +67,16 @@ I metodi di registrazione devono essere statici + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings Il metodo di registrazione '{0}' contiene stringhe in formato non valido diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf index a8c79393a42f23..bd03905bfba997 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf @@ -67,6 +67,16 @@ ログ メソッドは静的である必要があります + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings ログ メソッド '{0}' に、形式の正しくない文字列が含まれています diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf index 0b77d9c65adb5f..eea8ef2203ac1d 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf @@ -67,6 +67,16 @@ 로깅 메서드는 정적이어야 함 + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings 로깅 메서드 '{0}'에 잘못된 형식의 문자열이 포함되어 있습니다. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf index 2784dfa601576b..6dbecb86f7fc43 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf @@ -67,6 +67,16 @@ Metody rejestrowania muszą być statyczne + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings Metoda rejestrowania „{0}” zawiera źle sformułowane ciągi formatu diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf index 22b9fabb3b2965..f7de3a39c5a055 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf @@ -67,6 +67,16 @@ Os métodos de registro em log devem ser estáticos + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings O método de registro '{0}' contém strings de formato malformado diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf index 4446666caf4828..9599e0f6b9b809 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf @@ -67,6 +67,16 @@ Методы ведения журнала должны быть статическими + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings Метод ведения журнала событий "{0}" содержит строки неправильного формата diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf index fb21d7e0bd62ed..529a109ef75304 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf @@ -67,6 +67,16 @@ Günlüğe kaydetme yöntemleri statik olmalıdır + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings '{0}' günlüğe kaydetme yöntemi hatalı biçimlendirilmiş biçim dizeleri içeriyor diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf index 021f321ddf4b9f..879c6a773643a1 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -67,6 +67,16 @@ 日志记录方法必须为静态方法 + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings 日志记录方法“{0}”包含格式错误的字符串 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf index c50c7054e6ee2a..42061caa455c27 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -67,6 +67,16 @@ 記錄方法必須是靜態 + + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Logging method '{0}' contains malformed format strings 記錄方法 '{0}' 包含格式錯誤的格式字串 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index 462111ad00c372..dc677e81cfc4a0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -4,10 +4,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using SourceGenerators.Tests; using Xunit; @@ -108,7 +110,7 @@ partial class C {{ [LoggerMessage({argumentList})] static partial void M1(ILogger logger, string foo); - + [LoggerMessage({argumentList})] static partial void M2(ILogger logger, LogLevel level, string foo); }} @@ -911,6 +913,56 @@ static partial void M1(ILogger logger) Assert.Equal(DiagnosticDescriptors.LoggingMethodHasBody.Id, diagnostics[0].Id); } + [Fact] + public async Task LanguageVersionTest() + { + string source = """ + using Microsoft.Extensions.Logging; + + internal partial class Program + { + static void Main() { } + + [LoggerMessage( + EventId = 0, + Level = LogLevel.Critical, + Message = "Could not open socket to `{hostName}`")] + static partial void CouldNotOpenSocket(ILogger logger, string hostName); + } + """; + + Assembly[]? refs = new[] { typeof(ILogger).Assembly, typeof(LoggerMessageAttribute).Assembly }; + + // Run the generator with C# 7.0 and verify that it fails. + var (diagnostics, generatedSources) = await RoslynTestUtils.RunGenerator( + new LoggerMessageGenerator(), refs, new[] { source }, includeBaseReferences: true, LanguageVersion.CSharp7).ConfigureAwait(false); + + Assert.NotEmpty(diagnostics); + Assert.Equal("SYSLIB1026", diagnostics[0].Id); + Assert.Empty(generatedSources); + + // Run the generator with C# 8.0 and verify that it succeeds. + (diagnostics, generatedSources) = await RoslynTestUtils.RunGenerator( + new LoggerMessageGenerator(), refs, new[] { source }, includeBaseReferences: true, LanguageVersion.CSharp8).ConfigureAwait(false); + + Assert.Empty(diagnostics); + Assert.Single(generatedSources); + + // Compile the generated code with C# 7.0 and verify that it fails. + CSharpParseOptions parseOptions = new CSharpParseOptions(LanguageVersion.CSharp7); + SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(generatedSources[0].SourceText.ToString(), parseOptions); + var diags = syntaxTree.GetDiagnostics().ToArray(); + Assert.Equal(1, diags.Length); + // error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + Assert.Equal("CS8107", diags[0].Id); + + // Compile the generated code with C# 8.0 and verify that it succeeds. + parseOptions = new CSharpParseOptions(LanguageVersion.CSharp8); + syntaxTree = SyntaxFactory.ParseSyntaxTree(generatedSources[0].SourceText.ToString(), parseOptions); + diags = syntaxTree.GetDiagnostics().ToArray(); + Assert.Equal(0, diags.Length); + } + private static async Task> RunGenerator( string code, bool wrap = true, diff --git a/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs b/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs index 474686189fb126..141fc6b9c7f9ae 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs @@ -105,5 +105,12 @@ internal sealed class DiagDescriptors : DiagDescriptorsBase messageFormat: SR.InaccessibleValidationAttributeMessage, category: Category, defaultSeverity: DiagnosticSeverity.Info); + + public static DiagnosticDescriptor OptionsUnsupportedLanguageVersion { get; } = Make( + id: "SYSLIB1216", + title: SR.OptionsUnsupportedLanguageVersionTitle, + messageFormat: SR.OptionsUnsupportedLanguageVersionMessage, + category: Category, + defaultSeverity: DiagnosticSeverity.Error); } } diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs b/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs index 07ea7de51bf9a4..0c8e216e488c7f 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs @@ -143,6 +143,13 @@ public IReadOnlyList GetValidatorTypes(IEnumerable<(TypeDeclarati results.AddRange(_synthesizedValidators.Values); _synthesizedValidators.Clear(); + if (results.Count > 0 && _compilation is CSharpCompilation { LanguageVersion : LanguageVersion version and < LanguageVersion.CSharp8 }) + { + // we only support C# 8.0 and above + Diag(DiagDescriptors.OptionsUnsupportedLanguageVersion, null, version.ToDisplayString(), LanguageVersion.CSharp8.ToDisplayString()); + return new List(); + } + return results; } diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx index ef074f147f915e..6293431eb7f90e 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/Strings.resx @@ -207,4 +207,10 @@ Validation attribute on the member is inaccessible from the validator type.. + + C# language version not supported by the source generator. + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf index fadfdec9e3b7ad..7054599d224576 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - Typ {0} již implementuje metodu Validate. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Typ už obsahuje implementaci metody Validate. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] nelze použít pro statickou třídu {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - OptionsValidatorAttribute nelze použít pro statickou třídu. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - U polí nebo vlastností s otevřeným obecným typem {0} nelze použít [ValidateObjectMembers] nebo [ValidateEnumeratedItems]. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - U polí nebo vlastností s otevřenými obecnými typy nelze použít ValidateObjectMembersAttribute nebo ValidateEnumeratedItemsAttribute. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Atributy ověřování nelze použít u konstantního ani statického člena {0}. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Nelze ověřit konstanty, statická pole ani vlastnosti. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Existuje cyklický odkaz obsahující typ {0}, který brání jeho použití pro statické ověření. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Nepodporované cyklické odkazy v typech modelů. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - Typ {0} neimplementuje požadované rozhraní IValidateOptions<{1}> . + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Typ anotovaný třídou OptionsValidatorAttribute neimplementuje nezbytné rozhraní. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Ověřovací atribut „{0}“ u člena „{1}“ není přístupný z typu validátoru „{2}“. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Ověřovací atribut u člena není přístupný z typu validátoru. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Ověřovací atributy nelze použít u privátního pole nebo vlastnosti {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Nelze ověřit privátní pole nebo vlastnosti. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - Typ {0} nemá žádná pole ani vlastnosti k ověření, na které odkazuje člen {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Typ člena nemá žádná pole ani vlastnosti k ověření. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - Typ {0} nemá žádná pole ani vlastnosti k ověření, na které odkazuje typ {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Typ nemá žádná pole ani vlastnosti k ověření. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] nelze použít u členů typu {0}, protože neimplementuje rozhraní IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Typ členu není výčtový. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Typ validátoru s hodnotou null zadaný v atributech [ValidateObjectMembers] nebo [ValidateEnumeratedItems]. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Pro atributy ValidateObjectMembersAttribute nebo ValidateEnumeratedItemsAttribute byl specifikovaný typ validátoru s hodnotou null. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Typ {0} obsahuje validační anotace, ale člen {1} neurčuje [ValidateEnumeratedItems], což může být přehlédnutí. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - U člena potenciálně chybí ověření výčtu. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Typ {0} obsahuje validační anotace, ale člen {1} neurčuje [ValidateObjectMembers], což může být přehlédnutí. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - U člena potenciálně chybí přenositelné ověření. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - Typ validátoru {0} nemá konstruktor bez parametrů. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validátory používané pro přenositelné nebo výčtové ověřování musí mít konstruktor bez parametrů. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf index badb9618ac043b..5f6febba85c205 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - Der Typ "{0}" implementiert bereits die Validate-Methode. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Ein Typ enthält bereits eine Implementierung der Validate-Methode. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] kann nicht auf die statische Klasse "{0}" angewendet werden. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - "OptionsValidatorAttribute" kann nicht auf eine statische Klasse angewendet werden. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - "ValidateObjectMembers" oder "ValidateEnumeratedItems" kann nicht für Felder oder Eigenschaften mit offenem generischen Typ {0} verwendet werden. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - "ValidateObjectMembersAttribute" oder "ValidateEnumeratedItemsAttribute" kann nicht für Felder oder Eigenschaften mit offenen generischen Typen verwendet werden. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Validierungsattribute können nicht auf konstanten oder statischen Member {0} angewendet werden. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Konstanten, statische Felder oder Eigenschaften können nicht überprüft werden. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Es gibt einen Zirkelverweis, der den Typ "{0}" verhindert, dass er für die statische Validierung verwendet wird. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Nicht unterstützte Zirkelverweise in Modelltypen. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - Der Typ "{0}" implementiert nicht die erforderliche IValidateOptions<{1}>-Schnittstelle. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Ein mit "OptionsValidatorAttribute" versehener Typ implementiert nicht die erforderliche Schnittstelle. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Auf das Validierungsattribut "{0}" für den Member "{1}" kann vom Validierungssteuerelementtyp "{2}" nicht zugegriffen werden. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Auf das Validierungsattribut für den Member kann vom Validierungssteuerelementtyp nicht zugegriffen werden. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Validierungsattribute können nicht auf private Felder oder Eigenschaften {0} angewendet werden. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Private Felder oder Eigenschaften können nicht überprüft werden. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - Der Typ "{0}" weist keine zu überprüfenden Felder oder Eigenschaften auf, auf die von Member "{1}" verwiesen wird. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Ein Membertyp weist keine zu überprüfenden Felder oder Eigenschaften auf. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - Der Typ "{0}" weist keine zu überprüfenden Felder oder Eigenschaften auf, auf die vom Typ "{1}" verwiesen wird. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Ein Typ weist keine zu überprüfenden Felder oder Eigenschaften auf. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] kann nicht für Member vom Typ "{0}" verwendet werden, da es IEnumerable<T> nicht implementiert. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Der Membertyp ist nicht aufzählbar. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Der in den Attributen [ValidateObjectMembers] oder [ValidateEnumeratedItems] angegebene NULL-Validierungssteuerelementtyp. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Für die Attribute "ValidateObjectMembersAttribute" oder "ValidateEnumeratedItemsAttribute" wurde ein NULL-Validierungssteuerelementtyp angegeben. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Der Typ "{0}" weist Validierungsanmerkungen auf, der Member "{1}" gibt jedoch keine [ValidateEnumeratedItems] an, die eine Vorhersage darstellen könnten. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Dem Mitglied fehlt möglicherweise eine aufzählbare Validierung. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Der Typ "{0}" weist Validierungsanmerkungen auf, aber Member "{1}" gibt [ValidateObjectMembers] nicht an, was ein Versehen sein könnte. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Dem Member fehlt möglicherweise die transitive Validierung. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - Der Validierungssteuerelementtyp "{0}" hat keinen parameterlosen Konstruktor. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validierungssteuerelemente, die für die transitive oder enumerierbare Validierung verwendet werden, müssen über einen Konstruktor ohne Parameter verfügen. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf index 9637c745a081e0..84c12b9739ab1a 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - El tipo {0} ya implementa el método Validate. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Un tipo ya incluye una implementación del método “Validate”. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - No se puede aplicar [OptionsValidator] a la clase estática {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - “OptionsValidatorAttribute” no se puede aplicar a una clase estática. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - No se puede usar [ValidateObjectMembers] ni [ValidateEnumeratedItems] en campos o propiedades con tipos genéricos abiertos {0}. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - No se puede usar “ValidateObjectMembersAttribute” o “ValidateEnumeratedItemsAttribute” en campos o propiedades con tipos genéricos abiertos. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - No se pueden aplicar atributos de validación a un miembro {0}constante o estático. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - No se pueden validar constantes, campos estáticos ni propiedades. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Hay una referencia de tipo circular que implica al tipo {0} que impide que se use para la validación estática. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Referencias circulares no admitidas en los tipos de modelo. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - El tipo {0} no implementa la interfaz IValidateOptions<{1}> necesaria. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Un tipo anotado con “OptionsValidatorAttribute” no implementa la interfaz necesaria. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - No se puede obtener acceso al atributo de validación '{0}' en el miembro '{1}' desde el tipo de validador '{2}'. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - No se puede obtener acceso al atributo de validación en el miembro desde el tipo de validador. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - No se pueden aplicar atributos de validación a la propiedad o campo privado {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - No se pueden validar los campos o propiedades privadas. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - El tipo {0} no tiene campos ni propiedades para validar, al que hace referencia el tipo {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Un tipo de miembro no tiene campos ni propiedades para validar. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - El tipo {0} no tiene campos ni propiedades para validar, al que hace referencia el tipo {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Un tipo no tiene campos ni propiedades para validar. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] no se puede usar en miembros de tipo {0} porque no implementa IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - El tipo de miembro no es enumerable. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Se especificó un tipo de validador nulo en los atributos [ValidateObjectMembers] o [ValidateEnumeratedItems]. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Se especificó un tipo de validador nulo para los atributos “ValidateObjectMembersAttribute” o “ValidateEnumeratedItemsAttribute”. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - El tipo {0} tiene anotaciones de validación, pero el miembro {1} no especifica [ValidateEnumeratedItems], lo que podría ser un error. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Posiblemente falta la validación enumerable en el miembro. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - El tipo {0} tiene anotaciones de validación, pero el miembro {1} no especifica [ValidateObjectMembers], lo que podría ser un error. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Posiblemente falta la validación transitiva en el miembro. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - El tipo de validador {0} no tiene un constructor sin parámetros. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Los validadores usados para la validación transitiva o enumerable deben tener un constructor sin parámetros. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf index 93817f52c7ddf7..58a27f1e4b33cb 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - Le type {0} implémente déjà la méthode Validate. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Un type inclut déjà une implémentation de la méthode 'Validate'. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] ne peut pas être appliqué à la classe statique {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' ne peut pas être appliqué à une classe statique. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Impossible d’utiliser [ValidateObjectMembers] ou [ValidateEnumeratedItems] sur des champs ou des propriétés avec un type générique ouvert {0}. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Impossible d’utiliser 'ValidateObjectMembersAttribute' ou 'ValidateEnumeratedItemsAttribute' sur des champs ou des propriétés avec des types génériques ouverts. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Impossible d’appliquer les attributs de validation au membre constant ou statique {0}. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Impossible de valider les constantes, les champs statiques ou les propriétés. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Une référence de type circulaire implique un type {0} l’empêche d’être utilisé pour la validation statique. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Références circulaires non prises en charge dans les types de modèle. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - Le type {0} n’implémente pas l’interface<{1}> IValidateOptions requise. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Un type annoté avec 'OptionsValidatorAttribute' n’implémente pas l’interface nécessaire. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - L’attribut de validation '{0}' sur le membre '{1}' n’est pas accessible à partir du type de validateur '{2}'. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - L’attribut de validation sur le membre n’est pas accessible à partir du type de validateur. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Impossible d’appliquer les attributs de validation au champ privé ou à la propriété {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Impossible de valider les champs ou propriétés privés. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - Le type {0} n’a aucun champ ou propriété à valider, référencé à partir du membre {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Un type de membre n’a aucun champ ou propriété à valider. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - Le type {0} n’a pas de champs ou de propriétés à valider, référencé par type {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Un type n’a pas de champs ou de propriétés à valider. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] ne peut pas être utilisé sur des membres de type {0}, car il n’implémente pas IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Le type de membre n’est pas énumérable. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Type de validateur Null spécifié dans les attributs [ValidateObjectMembers] ou [ValidateEnumeratedItems]. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Type de validateur Null spécifié pour les attributs 'ValidateObjectMembersAttribute' ou 'ValidateEnumeratedItemsAttribute'. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Le type {0} a des annotations de validation, mais le membre {1} ne spécifie pas [ValidateEnumeratedItems] qui peut être une supervision. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Le membre n’a peut-être pas de validation énumérable. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Le type {0} a des annotations de validation, mais le membre {1} ne spécifie pas [ValidateObjectMembers] qui pourrait être une méthode de récupération. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Le membre n’a peut-être pas de validation transitive. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - Le type de validateur {0} n’a pas de constructeur sans paramètre. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Les validateurs utilisés pour la validation transitive ou énumérable doivent avoir un constructeur sans paramètres. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf index b80d8e27bcec22..2355a93c01db99 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - Il tipo {0} implementa già il metodo Validate. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Un tipo include già un'implementazione del metodo 'Validate'. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - impossibile applicare [OptionsValidator] alla classe statica {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' non può essere applicato a una classe statica. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Non è possibile usare [ValidateObjectMembers] o [ValidateEnumeratedItems] in campi o proprietà con tipo generico aperto {0}. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Non è possibile usare 'ValidateObjectMembersAttribute' o 'ValidateEnumeratedItemsAttribute' nei campi o nelle proprietà con tipi generici aperti. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Non è possibile applicare attributi di convalida a un membro costante o statico {0}. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Non è possibile convalidare costanti, campi statici o proprietà. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Esiste un riferimento di tipo circolare che interessa il tipo {0} e ne impedisce l'utilizzo per la convalida statica. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Riferimenti circolari non supportati nei tipi di modello. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - Il tipo {0} non implementa l'interfaccia IValidateOptions<{1}> richiesta. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Un tipo annotato con 'OptionsValidatorAttribute' non implementa l'interfaccia necessaria. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - L'attributo di convalida '{0}' nel membro '{1}' non è accessibile dal tipo di validator '{2}'. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - L'attributo di convalida nel membro non è accessibile dal tipo di validator. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Non è possibile applicare gli attributi di convalida al campo privato o alla proprietà {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Non è possibile convalidare proprietà o campi privati. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - Il tipo {0} non contiene campi o proprietà da convalidare, riferiti dal membro {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Un tipo di membro non contiene campi o proprietà da convalidare. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - Il tipo {0} non contiene campi o proprietà da convalidare, riferiti per tipo {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Un tipo non contiene campi o proprietà da convalidare. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] non può essere usato nei membri di tipo {0} perché non implementa IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Il tipo di membro non è enumerabile. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Tipo di validator Null specificato negli attributi [ValidateObjectMembers] o [ValidateEnumeratedItems]. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Tipo di validator Null specificato per gli attributi 'ValidateObjectMembersAttribute' o 'ValidateEnumeratedItemsAttribute'. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Il tipo {0} include annotazioni di convalida, ma il membro {1} non specifica [ValidateEnumeratedItems] che potrebbe essere una supervisione. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Convalida enumerabile potenzialmente mancante nel membro. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Il tipo {0} include annotazioni di convalida, ma il membro {1} non specifica [ValidateObjectMembers] che potrebbe essere una supervisione. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Il membro potrebbe non avere una convalida transitiva. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - Il tipo di convalida {0} non dispone di un costruttore senza parametri. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - I convalidatori usati per la convalida transitiva o enumerabile devono avere un costruttore senza parametri. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf index b9b44dd4afd5e5..60e9a7db80c8d4 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - 型 {0} に Validate メソッドが既に実装されています。 + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - 型には 'Validate' メソッドの実装が既に含まれています。 + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - 静的クラス {0} には [OptionsValidator] を適用できません。 + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' は静的クラスに適用できません。 + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - [ValidateObjectMembers] または [ValidateEnumeratedItems] は、オープンジェネリック型 {0} を持つフィールドまたはプロパティでは使用できません。 + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - 'ValidateObjectMembersAttribute' または 'ValidateEnumeratedItemsAttribute' は、オープンジェネリック型を持つフィールドまたはプロパティでは使用できません。 + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - 定数または静的メンバー {0} に検証属性を適用できません。 + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - 定数、静的フィールド、またはプロパティを検証できません。 + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - 型{0}を含む循環型参照があるため、静的検証に使用できません。 + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - モデル型でサポートされていない循環参照です。 + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - 必要な IValidateOptions<{1}> インターフェイスが型 {0} に実装されていません。 + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - 'OptionsValidatorAttribute' の注釈が付けられた型が、必要とされるインターフェイスを実装していません。 + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - メンバー '{0}' の検証属性 '{1}' は、検証コントロールの種類 '{2}'からアクセスできません。 + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - メンバーの検証属性は、検証コントロールの種類からアクセスできません... + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - プライベート フィールドまたはプロパティ {0} には検証属性を適用できません。 + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - プライベート フィールドまたはプロパティを検証できません。 + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - 型 {0} にメンバー {1} から参照されている検証対象のフィールドまたはプロパティがありません。 + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - メンバー型に検証対象のフィールドまたはプロパティがありません。 + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - 型 {0} に型 {1} で参照されている検証対象のフィールドまたはプロパティがありません。 + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - 型に検証対象のフィールドまたはプロパティがありません。 + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] は IEnumerable<T> を実装していないため、型 {0} のメンバーでは使用できません。 + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - メンバー型は列挙型ではありません。 + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - [ValidateObjectMembers] 属性または [ValidateEnumeratedItems] 属性で null のバリデーター型が指定されています。 + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - 'ValidateObjectMembersAttribute' 属性または 'ValidateEnumeratedItemsAttribute' 属性に対して NULL のバリデーター型が指定されています。 + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - 型 {0} には検証の注釈がありますが、メンバー {1} では [ValidateEnumeratedItem] が指定されていません。これは誤りである可能性があります。 + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - 列挙型の検証がメンバーに存在しない可能性があります。 + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - 型 {0} には検証の注釈がありますが、メンバー {1} では [ValidateObjectMembers] が指定されていません。これは誤りである可能性があります。 + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - メンバーに推移性の検証がない可能性があります。 + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - バリデーター型 {0} にパラメーターなしのコンストラクターがありません。 + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - 推移性または列挙型の検証に使用されるバリデーターには、パラメーターのないコンストラクターが必要です。 + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf index 45819c9f750a5a..e350b2f6f437de 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - 형식 {0}은(는) Validate 메서드를 이미 구현하고 있습니다. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - 형식에 'Validate' 메서드 구현이 이미 포함되어 있습니다. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator]은(는) 정적 클래스 {0}에 적용할 수 없습니다. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute'는 정적 클래스에 적용할 수 없습니다. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - 열린 제네릭 형식 {0}의 필드 또는 속성에는 [ValidateObjectMembers] 또는 [ValidateEnumeratedItems]을(를) 사용할 수 없습니다. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - 열린 제네릭 형식의 필드 또는 속성에는 'ValidateObjectMembersAttribute' 또는 'ValidateEnumeratedItemsAttribute'를 사용할 수 없습니다. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - 상수 또는 정적 멤버 {0}에 유효성 검사 특성을 적용할 수 없습니다. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - 상수, 정적 필드 또는 속성을 확인할 수 없습니다. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - 정적 유효성 검사에 사용할 수 없으므로 형식 {0} 관련된 순환 형식 참조가 있습니다. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - 모델 형식에 지원되지 않는 순환 참조가 있습니다. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - 형식 {0}은(는) 필요한 IValidateOptions<{1}> 인터페이스를 구현하지 않습니다. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - 'OptionsValidatorAttribute'로 주석이 추가된 형식은 필요한 인터페이스를 구현하지 않습니다. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - 유효성 검사기 유형 '{2}'에서 '{1}' 멤버의 '{0}' 유효성 검사 특성에 액세스할 수 없습니다. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - 유효성 검사기 유형에서 멤버의 유효성 검사 특성에 액세스할 수 없습니다. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - 프라이빗 필드 또는 속성 {0}에 유효성 검사 특성을 적용할 수 없습니다. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - 프라이빗 필드 또는 속성의 유효성을 검사할 수 없습니다. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - 형식 {0}은(는) 유효성을 검사할 필드 또는 속성이 없으므로 멤버 {1}을(를) 참조합니다. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - 멤버 형식에 유효성을 검사할 필드 또는 속성이 없습니다. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - 형식 {0}은(는) 유효성을 검사할 필드 또는 속성이 없으므로 형식 {1}을(를) 참조합니다. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - 형식에 유효성을 검사할 필드 또는 속성이 없습니다. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems]은(는) IEnumerable<T>을(를) 구현하지 않으므로 형식 {0}의 멤버에 사용할 수 없습니다. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - 멤버 형식을 열거할 수 없습니다. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - [ValidateObjectMembers] 또는 [ValidateEnumeratedItems] 특성에 Null 유효성 검사기 형식이 지정되었습니다. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - 'ValidateObjectMembersAttribute' 또는 'ValidateEnumeratedItemsAttribute' 특성에 Null 유효성 검사기 형식이 지정되었습니다. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - 형식 {0}은(는) 유효성 검사 주석이 있지만 멤버 {1}은(는) 참조할 수 있는 [ValidateEnumeratedItems]을(를) 지정하지 않습니다. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - 멤버에 열거 가능한 유효성 검사가 누락되었을 수 있습니다. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - 형식 {0}은(는) 유효성 검사 주석이 있지만 멤버 {1}은(는) 참조할 수 있는 [ValidateObjectMembers]을(를) 지정하지 않습니다. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - 멤버에 전이적 유효성 검사가 누락되었을 수 있습니다. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - 유효성 검사기 형식 {0}은(는) 매개 변수가 없는 생성자가 없습니다. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - 전이적 또는 열거형 유효성 검사에 사용되는 유효성 검사기에는 매개 변수가 없는 생성자가 있어야 합니다. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf index 0b57a0ac378924..edaf8b9d00e9ba 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - Typ {0} już implementuje metodę Validate. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Typ zawiera już implementację metody „Validate”. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - Nie można zastosować elementu [OptionsValidator] do klasy statycznej {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - Nie można zastosować elementu „OptionsValidatorAttribute” do klasy statycznej. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Nie można użyć atrybutu [ValidateObjectMembers] lub [ValidateEnumeratedItems] w polach lub właściwościach z otwartymi typami ogólnymi {0}. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Nie można użyć atrybutu „ValidateObjectMembersAttribute” lub „ValidateEnumeratedItemsAttribute” w polach lub właściwościach z otwartymi typami ogólnymi. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Nie można zastosować atrybutów walidacji do stałych lub statycznych elementów członkowskich {0}. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Nie można zweryfikować stałych, pól statycznych lub właściwości. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Istnieje cykliczne odwołanie do typu dotyczące typu {0} uniemożliwiające użycie go do weryfikacji statycznej. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Nieobsługiwane odwołania cykliczne w typach modeli. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - Typ {0} nie implementuje wymaganego interfejsu IValidateOptions<{1}>. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Typ z adnotacją „OptionsValidatorAttribute” nie implementuje wymaganego interfejsu. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Atrybut walidacji „{0}” elementu członkowskiego „{1}” jest niedostępny z typu modułu sprawdzania poprawności „{2}”. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Atrybut walidacji elementu członkowskiego jest niedostępny z typu modułu sprawdzania poprawności. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Nie można zastosować atrybutów weryfikacji do pola prywatnego lub właściwości {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Nie można zweryfikować prywatnych pól lub właściwości. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - Typ {0} nie ma pól ani właściwości do zweryfikowania, do których odwołuje się element członkowski {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Typ elementu członkowskiego nie ma pól ani właściwości do zweryfikowania. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - Typ {0} nie ma pól ani właściwości do zweryfikowania, do których odwołuje się typ {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Typ nie ma pól ani właściwości do zweryfikowania. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - Atrybutu [ValidateEnumeratedItems] nie można używać w przypadku elementów członkowskich typu {0}, ponieważ nie implementuje interfejsu IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Nie można wyliczyć typu elementu członkowskiego. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - W atrybutach [ValidateObjectMembers] lub [ValidateEnumeratedItems] określono typ modułu sprawdzania poprawności o wartości null. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Określono typ modułu sprawdzania poprawności o wartości null dla atrybutu „ValidateObjectMembersAttribute” lub „ValidateEnumeratedItemsAttribute”. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Typ {0} ma adnotacje walidacji, ale element członkowski {1} nie określa atrybutu [ValidateEnumeratedItems], co może być przeoczeniem. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - W elemencie członkowskim może brakować walidacji możliwej do wyliczenia. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Typ {0} ma adnotacje walidacji, ale element członkowski {1} nie określa atrybutu [ValidateObjectMembers], co może być przeoczeniem. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - W przypadku elementu członkowskiego może potencjalnie brakować weryfikacji przechodniej. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - Typ modułu sprawdzania poprawności {0} nie ma konstruktora bez parametrów. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Moduły sprawdzania poprawności używane do weryfikacji przechodniej lub weryfikacji możliwej do wyliczenia muszą mieć konstruktora bez żadnych parametrów. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf index 4afa1d6763db8b..f62a1ef241e372 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - O tipo {0} já implementa o método Validar. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Um tipo já inclui uma implementação do método "Validar". + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] não pode ser aplicado à classe estática {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - "OptionsValidatorAttribute" não pode ser aplicado a uma classe estática. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Não é possível usar [ValidateObjectMembers] ou [ValidateEnumeratedItems] em campos ou propriedades com o tipo genérico aberto {0}. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Não é possível usar "ValidateObjectMembersAttribute" ou "ValidateEnumeratedItemsAttribute" em campos ou propriedades com tipos genéricos abertos. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Não é possível aplicar atributos de validação a um membro constante ou estático {0}. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Não é possível validar constantes, campos estáticos ou propriedades. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Há uma referência de tipo circular que envolve o tipo {0} que a impede de ser usada para validação estática. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Referências circulares sem suporte em tipos de modelo. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - O tipo {0} não implementa a interface IValidateOptions<{1}> necessária. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Um tipo anotado com "OptionsValidatorAttribute" não implementa a interface necessária. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - O atributo de validação '{0}' no membro '{1}' está inacessível do tipo de validador '{2}'. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - O atributo de validação no membro está inacessível do tipo de validador. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Não é possível aplicar atributos de validação a um campo privado ou propriedade {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Não é possível validar propriedades ou campos privados. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - O tipo {0} não tem campos ou propriedades para validar, referenciados do membro {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Um tipo de membro não tem campos ou propriedades a serem validados. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - O tipo {0} não tem campos ou propriedades para validar, referenciados por tipo {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Um tipo não tem campos ou propriedades a serem validados. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] não pode ser usado em membros do tipo {0}, pois ele não implementa IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - O tipo de membro não é enumerável. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Tipo de validador nulo especificado nos atributos [ValidateObjectMembers] ou [ValidateEnumeratedItems]. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Tipo de validador nulo especificado para os atributos "ValidateObjectMembersAttribute" ou "ValidateEnumeratedItemsAttribute". + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - O tipo {0} tem anotações de validação, mas o membro {1} não especifica [ValidateEnumeratedItems], o que pode ser uma desatenção. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Membro potencialmente ausente na validação enumerável. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - O tipo {0} tem anotações de validação, mas o membro {1} não especifica [ValidateObjectMembers], o que pode ser uma desatenção. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Membro potencialmente ausente na validação transitiva. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - O tipo de validador {0} não tem um construtor sem parâmetros. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Os validadores usados para validação transitiva ou enumerável devem ter um construtor sem parâmetros. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf index 02fb57d5497df9..b8069e4266ae37 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - Тип {0} уже реализует метод Validate. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Тип уже содержит реализацию метода Validate. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] невозможно применить к статическому классу {0}. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - Параметр OptionsValidatorAttribute не может быть применен к статическому классу. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Нельзя использовать [ValidateObjectMembers] или [ValidateEnumeratedItems] для полей или свойств с открытыми универсальными типами {0}. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Нельзя использовать "ValidateObjectMembersAttribute" или "ValidateEnumeratedItemsAttribute" для полей или свойств с открытыми универсальными типами. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Не удалось применить атрибуты проверки к константе или статическому элементу {0}. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Не удалось проверить константы, статические поля или свойства. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Существует циклическая ссылка на тип, включающая тип {0}, предотвращающий его использование для статической проверки. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Неподдерживаемые циклические ссылки в типах моделей. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - Тип {0} не реализует требуемый интерфейс IValidateOptions<{1}>. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - Тип с аннотацией OptionsValidatorAttribute не реализует необходимый интерфейс. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Атрибут проверки "{0}" элемента "{1}" недоступен из типа средства проверки "{2}". + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Атрибут проверки элемента недоступен из типа средства проверки. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Не удается применить атрибуты проверки к закрытому полю или свойству {0}. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Не удается проверить частные поля или свойства. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - Тип {0} не содержит полей или свойств для проверки, на которые ссылается из элемента {1}. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Тип элемента не имеет полей или свойств для проверки. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - Тип {0} не содержит полей или свойств для проверки, на которые ссылается тип {1}. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Тип не имеет полей или свойств для проверки. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] не может использоваться для элементов типа {0}, так как он не реализует IEnumerable<T>. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Тип элемента не является перечисляемым. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Тип проверяющего элемента управления, указанный в [ValidateObjectMembers] или [ValidateEnumeratedItems] атрибутах, имеет значение NULL. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Для атрибутов ValidateObjectMembersAttribute или ValidateEnumeratedItemsAttribute указан тип проверяющего элемента управления NULL. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Тип {0} содержит примечания проверки, но элемент {1} не указывает [ValidateEnumeratedItems], который может быть задан. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Элемент потенциально пропускает перечисляемую проверку. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Тип {0} содержит примечания проверки, но элемент {1} не указывает [ValidateObjectMembers], который может быть задан. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Возможно, в элементе отсутствует транзитивная проверка. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - Тип проверяющего элемента управления {0} не имеет конструктора без параметров. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - У проверяющих элементов управления, используемых для транзитивной или перечисляемой проверки, должен быть конструктор без параметров. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf index 6743baba13c804..8cb34b9b6f900a 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - {0} türü Doğrulama yöntemini zaten uyguluyor. + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - Bir tür zaten 'Validate' yönteminin bir uygulamasını içeriyor. + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator], {0} statik sınıfına uygulanamıyor. + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' statik sınıfa uygulanamaz. + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - {0} açık genel türündeki alanlarda veya özelliklerde [ValidateObjectMembers] veya [ValidateEnumeratedItems] kullanılamaz. + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Açık genel türleri olan alanlarda veya özelliklerde 'ValidateObjectMembersAttribute' veya 'ValidateEnumeratedItemsAttribute' kullanılamaz. + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - Doğrulama öznitelikleri sabit veya statik üye {0} için geçerli değildir. + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - Sabitler, statik alanlar veya özellikler doğrulanamıyor. + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - Statik doğrulama için kullanılmasını engelleyen {0} türü içeren döngüsel bir tür başvurusu var. + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - Model türlerde döngüsel başvurular desteklenmiyor. + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - {0} türü gerekli IValidateOptions<{1}> arabirimini uygulamıyor. + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - 'OptionsValidatorAttribute' ile açıklama eklenmiş bir tür gerekli arabirimi uygulamıyor. + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - '{1}' adlı üye üzerindeki '{0}' doğrulama özniteliğine '{2}' doğrulayıcı türünden erişilemiyor. + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Üye üzerindeki doğrulama özniteliğine doğrulayıcı türünden erişilemiyor. + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - Doğrulama öznitelikleri, {0} özel alanına veya özelliğine uygulanamıyor. + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - Özel alanlar veya özellikler doğrulanamıyor. + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - {0} türünde doğrulanacak alan veya özellik yok, {1} üyesinden başvurulur. + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - Üye türünde doğrulanacak alan veya özellik yok. + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - {0} türünde doğrulanacak alan veya özellik yok, {1} türü tarafından başvurulur. + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - Türde doğrulanacak alan veya özellik yok. + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems], IEnumerable<T> uygulamadığından {0} türündeki üyeler üzerinde kullanılamıyor. + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - Üye türü numaralandırılabilir değil. + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - [ValidateObjectMembers] veya [ValidateEnumeratedItems] özniteliklerinde null doğrulayıcı türü belirtildi. + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - 'ValidateObjectMembersAttribute' veya 'ValidateEnumeratedItemsAttribute' öznitelikleri için null doğrulayıcı türü belirtildi. + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - {0} türünde doğrulama ek açıklamaları var, ancak {1} üyesi gözden kaçmış olabilecek [ValidateEnumeratedItems] belirtmiyor. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - Üyede numaralandırılabilir doğrulama eksik olabilir. + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - {0} türünde doğrulama ek açıklamaları var, ancak {1} üyesi gözden kaçmış olabilecek [ValidateObjectMembers] belirtmiyor. + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - Üyede geçişli doğrulama eksik olabilir. + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - {0} doğrulayıcı türü parametresiz bir oluşturucuya sahip değil. + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Geçişli veya numaralandırılabilir doğrulama için kullanılan doğrulayıcıların parametresi olmayan bir oluşturucusu olmalıdır. + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf index cd68a3a773332b..707dcb36c697b0 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - 类型 {0} 已实现 Validate 方法。 + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - 类型已包含“Validate”方法的实现。 + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] 无法应用于静态类 {0}。 + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - “OptionsValidatorAttribute”不能应用于静态类。 + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - 不能对具有开放泛型类型 {0} 的字段或属性使用 [ValidateObjectMembers] 或 [ValidateEnumeratedItems]。 + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - 不能对具有开放泛型类型的字段或属性使用 "ValidateObjectMembersAttribute" 或 "ValidateEnumeratedItemsAttribute"。 + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - 无法将验证属性应用于常量或静态成员 {0}。 + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - 无法验证常量、静态字段或属性。 + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - 存在一个循环类型引用,其中涉及的类型 {0} 阻止将其用于静态验证。 + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - 模型类型中不支持的循环引用。 + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - 类型 {0} 未实现所需的 IValidateOptions<{1}> 接口。 + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - 用 "OptionsValidatorAttribute" 批注的类型未实现必要的接口。 + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - 无法从验证程序类型“{2}”访问成员“{1}”上的验证属性“{0}”。 + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - 无法从验证程序类型访问成员上的验证属性。 + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - 无法将验证属性应用于专用字段或属性 {0}。 + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - 无法验证专用字段或属性。 + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - 类型 {0} 没有要验证的字段或属性,从成员 {1} 中引用。 + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - 成员类型没有要验证的字段或属性。 + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - 类型 {0} 没有要验证的字段或属性,由类型 {1} 引用。 + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - 类型没有要验证的字段或属性。 + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - 无法对类型 {0} 的成员使用 [ValidateEnumeratedItems],因为它未实现 IEnumerable<T>。 + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - 成员类型不可枚举。 + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - [ValidateObjectMembers] 或 [ValidateEnumeratedItems] 属性中指定的 Null 验证程序类型。 + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - 为“ValidateObjectMembersAttribute”或“ValidateEnumeratedItemsAttribute”属性指定的验证程序类型为 Null。 + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - 类型 {0} 具有验证注释,但成员 {1} 未指定 [ValidateEnumeratedItems],这可能是一种监督。 + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - 成员可能缺少可枚举验证。 + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - 类型 {0} 具有验证注释,但成员 {1} 未指定 [ValidateObjectMembers],这可能是一种监督。 + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - 成员可能缺少可传递验证。 + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - 验证程序类型 {0} 没有无参数构造函数。 + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - 用于可传递验证或可枚举验证的验证程序必须具有没有参数的构造函数。 + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf index f21a748ed078e7..f8087186cb294b 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -4,152 +4,162 @@ Type {0} already implements the Validate method. - 類型 {0} 已實作 [驗證] 方法。 + Type {0} already implements the Validate method. A type already includes an implementation of the 'Validate' method. - 類型已經包含 [驗證] 方法的實作。 + A type already includes an implementation of the 'Validate' method. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] 無法套用至靜態類別 {0}。 + [OptionsValidator] cannot be applied to static class {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 無法將 'OptionsValidatorAttribute' 套用至靜態類別。 + 'OptionsValidatorAttribute' can't be applied to a static class. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - 無法在有開放式泛型型別 {0} 的欄位或屬性上使用 [ValidateObjectMembers] 或 [ValidateEnumeratedItems]。 + Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - 無法在有開放式泛型型別的欄位或屬性上使用 'ValidateObjectMembersAttribute' 或 'ValidateEnumeratedItemsAttribute'。 + Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. Can't apply validation attributes to constant or static member {0}. - 無法將驗證屬性套用至常數或靜態成員 {0}。 + Can't apply validation attributes to constant or static member {0}. Can't validate constants, static fields or properties. - 無法驗證常數、靜態欄位或屬性。 + Can't validate constants, static fields or properties. There is a circular type reference involving type {0} preventing it from being used for static validation. - 有涉及類型 {0} 的循環類型參考讓它無法用於靜態驗證。 + There is a circular type reference involving type {0} preventing it from being used for static validation. Unsupported circular references in model types. - 模型類型中不支援的循環參考。 + Unsupported circular references in model types. Type {0} does not implement the required IValidateOptions<{1}> interface. - 類型 {0} 未實作必要的 IValidateOptions<{1}> 介面。 + Type {0} does not implement the required IValidateOptions<{1}> interface. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - 以 'OptionsValidatorAttribute' 附註的類型未實作必要的介面。 + A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - 無法從驗證程式類型 '{2}' 存取成員 '{1}' 上的驗證屬性 '{0}'。 + Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. Validation attribute on the member is inaccessible from the validator type.. - 無法從驗證程式類型存取成員上的驗證屬性。 + Validation attribute on the member is inaccessible from the validator type.. Can't apply validation attributes to private field or property {0}. - 無法將驗證屬性套用至私用欄位或屬性 {0}。 + Can't apply validation attributes to private field or property {0}. Can't validate private fields or properties. - 無法驗證私人欄位或屬性。 + Can't validate private fields or properties. Type {0} has no fields or properties to validate, referenced from member {1}. - 參照會員 {1},類型 {0} 沒有欄位或屬性可供驗證。 + Type {0} has no fields or properties to validate, referenced from member {1}. A member type has no fields or properties to validate. - 成員類型沒有欄位或屬性可供驗證。 + A member type has no fields or properties to validate. Type {0} has no fields or properties to validate, referenced by type {1}. - 參照類型 {1},類型 {0} 沒有欄位或屬性可供驗證。 + Type {0} has no fields or properties to validate, referenced by type {1}. A type has no fields or properties to validate. - 類型沒有欄位或屬性可供驗證。 + A type has no fields or properties to validate. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] 無法用於類型 {0} 的成員,因為其未實作 IEnumerable<T>。 + [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. Member type is not enumerable. - 成員類型無法列舉。 + Member type is not enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - [ValidateObjectMembers] 或 [ValidateEnumeratedItems] 屬性中指定的 Null 驗證程式類型。 + Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - 為 'ValidateObjectMembersAttribute' 或 'ValidateEnumeratedItemsAttribute' 屬性指定的 Null 驗證程式類型。 + Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - 成員 {0} 具備驗證註釋,但成員 {1} 未指定 [ValidateObjectMembers] (可能為監督)。 + Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. Member potentially missing enumerable validation. - 成員可能遺漏可列舉的驗證。 + Member potentially missing enumerable validation. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - 類型 {0} 具備驗證註釋,但成員 {1} 未指定 [ValidateObjectMembers] (可能為監督)。 + Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. Member potentially missing transitive validation. - 成員可能遺漏轉移的驗證。 + Member potentially missing transitive validation. Validator type {0} doesn't have a parameterless constructor. - 驗證程式類型 {0} 沒有無參數建構函式。 + Validator type {0} doesn't have a parameterless constructor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - 用於轉移或可列舉驗證的驗證程式必須具備沒有參數的建構函式。 + Validators used for transitive or enumerable validation must have a constructor with no parameters. diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs index b243ee50f361d9..f3e0513a885f22 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs @@ -1582,6 +1582,63 @@ public partial class FirstValidator : IValidateOptions Assert.Equal(DiagDescriptors.NotEnumerableType.Id, diagnostics[0].Id); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public async Task LanguageVersionTest() + { + string source = """ + using System; + using System.ComponentModel.DataAnnotations; + using Microsoft.Extensions.Options; + + public class FirstModel + { + [Required] + public string? P1 { get; set; } + } + + [OptionsValidator] + public partial class FirstModelValidator : IValidateOptions + { + } + """; + + Assembly [] refAssemblies = new [] + { + Assembly.GetAssembly(typeof(RequiredAttribute)), + Assembly.GetAssembly(typeof(OptionsValidatorAttribute)), + Assembly.GetAssembly(typeof(IValidateOptions)), + }; + + // Run the generator with C# 7.0 and verify that it fails. + var (diagnostics, generatedSources) = await RoslynTestUtils.RunGenerator( + new Generator(), refAssemblies.ToArray(), new[] { source }, includeBaseReferences: true, LanguageVersion.CSharp7).ConfigureAwait(false); + + Assert.NotEmpty(diagnostics); + Assert.Equal("SYSLIB1216", diagnostics[0].Id); + Assert.Empty(generatedSources); + + // Run the generator with C# 8.0 and verify that it succeeds. + (diagnostics, generatedSources) = await RoslynTestUtils.RunGenerator( + new Generator(), refAssemblies.ToArray(), new[] { source }, includeBaseReferences: true, LanguageVersion.CSharp8).ConfigureAwait(false); + + Assert.Empty(diagnostics); + Assert.Single(generatedSources); + + // Compile the generated code with C# 7.0 and verify that it fails. + CSharpParseOptions parseOptions = new CSharpParseOptions(LanguageVersion.CSharp7); + SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(generatedSources[0].SourceText.ToString(), parseOptions); + var diags = syntaxTree.GetDiagnostics().ToArray(); + Assert.Equal(1, diags.Length); + // error CS8107: Feature 'nullable reference types' is not available in C# 7.0. Please use language version 8.0 or greater. + Assert.Equal("CS8107", diags[0].Id); + + // Compile the generated code with C# 8.0 and verify that it succeeds. + parseOptions = new CSharpParseOptions(LanguageVersion.CSharp8); + syntaxTree = SyntaxFactory.ParseSyntaxTree(generatedSources[0].SourceText.ToString(), parseOptions); + diags = syntaxTree.GetDiagnostics().ToArray(); + Assert.Equal(0, diags.Length); + } + private static CSharpCompilation CreateCompilationForOptionsSource(string assemblyName, string source, string? refAssemblyPath = null) { // Ensure the generated source compiles diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx index c6d9021ea99672..6b8167e94b119a 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Resources/Strings.resx @@ -210,4 +210,10 @@ Validation attribute on the member is inaccessible from the validator type.. + + C# language version not supported by the source generator. + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx index c6d9021ea99672..6b8167e94b119a 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Resources/Strings.resx @@ -210,4 +210,10 @@ Validation attribute on the member is inaccessible from the validator type.. + + C# language version not supported by the source generator. + + + The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + \ No newline at end of file diff --git a/src/libraries/System.Text.Json/gen/Resources/Strings.resx b/src/libraries/System.Text.Json/gen/Resources/Strings.resx index 85d64b685f023d..519cbffa3ec09a 100644 --- a/src/libraries/System.Text.Json/gen/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/gen/Resources/Strings.resx @@ -1,17 +1,17 @@ - @@ -193,7 +193,7 @@ C# language version not supported by the source generator. - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. Constructor annotated with JsonConstructorAttribute is inaccessible. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf index cc88af350de1e5..41ce7674876442 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - Zdrojový generátor System.Text.Json není k dispozici v jazyce C#{0}. Použijte prosím jazykovou verzi {1} nebo vyšší. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Zdrojový generátor System.Text.Json není k dispozici v jazyce C#{0}. Použijte prosím jazykovou verzi {1} nebo vyšší. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf index d23d07843bb212..a0b49aa02c03f3 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - Der System.Text.Json-Quellgenerator ist in C# „{0}“ nicht verfügbar. Verwenden Sie die Sprachversion {1} oder höher. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Der System.Text.Json-Quellgenerator ist in C# „{0}“ nicht verfügbar. Verwenden Sie die Sprachversion {1} oder höher. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf index 989c5a8a02f263..bdd7876fa38cd3 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - El generador de origen System.Text.Json no está disponible en C# '{0}'. Use la versión de idioma {1} o superior. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + El generador de origen System.Text.Json no está disponible en C# '{0}'. Use la versión de idioma {1} o superior. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf index 4e1998a8f6e376..4b93e17edd6eb6 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - Le générateur de source System.Text.Json n'est pas disponible en C# '{0}'. Veuillez utiliser la version linguistique {1} ou supérieure. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Le générateur de source System.Text.Json n'est pas disponible en C# '{0}'. Veuillez utiliser la version linguistique {1} ou supérieure. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf index 5cb68b207cab19..cb163ff94ec4f9 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - Il generatore di origine System.Text.Json non è disponibile in C# '{0}'. Usare la versione del linguaggio {1} o successiva. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Il generatore di origine System.Text.Json non è disponibile in C# '{0}'. Usare la versione del linguaggio {1} o successiva. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf index a25a901571f489..9e3366a8bf09a2 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - System.Text.Json ソース ジェネレーターは C# '{0}' では使用できません。言語バージョン {1} 以上を使用してください。 + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + System.Text.Json ソース ジェネレーターは C# '{0}' では使用できません。言語バージョン {1} 以上を使用してください。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf index dec5ff53a5aa12..735e6d772f7c26 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - System.Text.Json 원본 생성기는 C# '{0}'에서 사용할 수 없습니다. {1} 이상의 언어 버전을 사용하세요. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + System.Text.Json 원본 생성기는 C# '{0}'에서 사용할 수 없습니다. {1} 이상의 언어 버전을 사용하세요. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf index bb1a603dbaf458..8282fa16aa908b 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - Generator źródła System.Text.Json nie jest dostępny w języku C# „{0}”. Użyj wersji językowej lub nowszej {1} . + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Generator źródła System.Text.Json nie jest dostępny w języku C# „{0}”. Użyj wersji językowej lub nowszej {1} . diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf index a4cb21e691b5dd..030a3f3302e729 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - O gerador de fonte System.Text.Json não está disponível em C# '{0}'. Use a versão do idioma {1} ou superior. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + O gerador de fonte System.Text.Json não está disponível em C# '{0}'. Use a versão do idioma {1} ou superior. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf index d1c3241bc43f22..556fa665267f30 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - Генератор исходного кода System.Text.Json не доступен в C# "{0}". Используйте языковую версию {1} или выше. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Генератор исходного кода System.Text.Json не доступен в C# "{0}". Используйте языковую версию {1} или выше. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf index 72b706fdc31a64..e74d8818167e3d 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - System.Text.Json kaynak oluşturucusu C# '{0}' içinde kullanılamıyor. Lütfen dil sürümü {1} veya üstü sürümü kullanın. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + System.Text.Json kaynak oluşturucusu C# '{0}' içinde kullanılamıyor. Lütfen dil sürümü {1} veya üstü sürümü kullanın. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf index 3450d312816e01..3ac4929b2b76dd 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - System.Text.Json 源生成器在 C#“{0}”中不可用。请使用{1}或更高版本的语言版本。 + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + System.Text.Json 源生成器在 C#“{0}”中不可用。请使用{1}或更高版本的语言版本。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf index 176989f5fc53a6..a194d8afc278d7 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -113,8 +113,8 @@ - The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. - C# '{0}' 中無法使用 System.Text.Json 來源產生器。請使用 {1} 或更新的語言版本。 + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + C# '{0}' 中無法使用 System.Text.Json 來源產生器。請使用 {1} 或更新的語言版本。 diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs index 98f2b71042332b..a554d2681d43d1 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs @@ -416,7 +416,7 @@ public void SupportedLanguageVersions_SucceedCompilation(LanguageVersion langVer using System.Text.Json.Serialization; namespace HelloWorld - { + { public class MyClass { public MyClass(int value) @@ -457,7 +457,7 @@ public void SupportedLanguageVersions_Memory_SucceedCompilation(LanguageVersion using System.Text.Json.Serialization; namespace HelloWorld - { + { public class MyClass { public MyClass( @@ -504,7 +504,7 @@ public void UnsupportedLanguageVersions_FailCompilation(LanguageVersion langVers using System.Text.Json.Serialization; namespace HelloWorld - { + { public class MyClass { public MyClass(int value) @@ -531,7 +531,7 @@ public partial class MyJsonContext : JsonSerializerContext var expectedDiagnostics = new DiagnosticData[] { - new(DiagnosticSeverity.Error, contextLocation, $"The System.Text.Json source generator is not available in C# '{langVersion.ToDisplayString()}'. Please use language version 9.0 or greater.") + new(DiagnosticSeverity.Error, contextLocation, $"The System.Text.Json source generator is not available in C# {langVersion.ToDisplayString()}. Please use language version 9.0 or greater.") }; CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics); From 52f3d10d7938e8748a43b25f69a4e6795e72822c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:11:07 -0700 Subject: [PATCH 040/345] Make DacValidateMD and DacValidateMethodTable more resilient (#90797) Make both methods more resilient to the case of invalid MethodDesc and MethodTable with value -1. Close #90691 Co-authored-by: Jan Vorlicek --- src/coreclr/debug/daccess/request.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 868593fae4651e..114900ffaf0365 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -135,11 +135,17 @@ BOOL DacValidateEEClass(PTR_EEClass pEEClass) BOOL DacValidateMethodTable(PTR_MethodTable pMT, BOOL &bIsFree) { + bIsFree = FALSE; + + if ((pMT == NULL) || dac_cast(pMT) == (TADDR)-1) + { + return FALSE; + } + // Verify things are right. BOOL retval = FALSE; EX_TRY { - bIsFree = FALSE; if (HOST_CDADDR(pMT) == HOST_CDADDR(g_pFreeObjectMethodTable)) { bIsFree = TRUE; @@ -182,7 +188,7 @@ BadMethodTable: ; BOOL DacValidateMD(PTR_MethodDesc pMD) { - if (pMD == NULL) + if ((pMD == NULL) || dac_cast(pMD) == (TADDR)-1) { return FALSE; } From 20d508bf9597c73a063eec535bcb2fd5cabc7837 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 12:50:30 -0700 Subject: [PATCH 041/345] [release/8.0-rc1] [wasm] Do not build mono libs with `-msimd128` (#90750) * [wasm] Do not build mono libs with `-msimd128` Make it optional, build only minimal set of code witch required `-msimd128` to separate library. Also provide "stub" nosimd version of this library. Choose the appropriate library during linking. * Fix build * Fix build of non-wasm platforms * Add simd options for wasi * Fix wasi build --------- Co-authored-by: Radek Doulik Co-authored-by: Larry Ewing --- .../Directory.Build.props | 2 ++ src/mono/CMakeLists.txt | 8 ----- src/mono/mono.proj | 6 ++++ src/mono/mono/mini/CMakeLists.txt | 25 +++++++++++++-- src/mono/mono/mini/interp/interp-nosimd.c | 31 +++++++++++++++++++ src/mono/mono/mini/interp/interp-simd.c | 2 ++ src/mono/mono/mini/interp/interp-simd.h | 2 ++ src/mono/mono/mini/interp/transform-simd.c | 4 +++ src/mono/wasi/build/WasiApp.Native.targets | 6 ++++ src/mono/wasi/runtime/CMakeLists.txt | 1 + src/mono/wasi/wasi.proj | 2 ++ src/mono/wasm/build/WasmApp.Native.targets | 6 ++++ src/mono/wasm/runtime/CMakeLists.txt | 1 + src/mono/wasm/wasm.proj | 3 +- 14 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 src/mono/mono/mini/interp/interp-nosimd.c diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index 13cf1fc895c8ac..5a96f57519aaf8 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -197,6 +197,8 @@ + + diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 66e92d80564363..a57cc52b0b110b 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -242,14 +242,6 @@ elseif(CLR_CMAKE_HOST_OS STREQUAL "emscripten") add_compile_options(-Wno-strict-prototypes) add_compile_options(-Wno-unused-but-set-variable) add_compile_options(-Wno-single-bit-bitfield-constant-conversion) - # Allow using WASM simd intrinsics in the interpreter - add_compile_options(-msimd128) - # Disable autovectorization (it is automatically turned on by msimd128) - add_compile_options(-disable-loop-vectorization) - add_compile_options(-disable-vectorization) - add_compile_options(-fno-vectorize) - add_compile_options(-fno-tree-vectorize) - add_compile_options(-fno-slp-vectorize) set(DISABLE_EXECUTABLES 1) # FIXME: Is there a cmake option for this ? set(DISABLE_SHARED_LIBS 1) diff --git a/src/mono/mono.proj b/src/mono/mono.proj index cf99f325ea5565..6be683f8e2eb2c 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -1061,6 +1061,12 @@ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true' and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-wasm-eh-wasm.a"> $(RuntimeBinDir)libmono-wasm-eh-wasm.a + <_MonoRuntimeArtifacts Condition="('$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true') and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-wasm-simd.a"> + $(RuntimeBinDir)libmono-wasm-simd.a + + <_MonoRuntimeArtifacts Condition="('$(TargetsBrowser)' == 'true' or '$(TargetsWasi)' == 'true') and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-wasm-nosimd.a"> + $(RuntimeBinDir)libmono-wasm-nosimd.a + <_MonoICorDebugArtifacts Condition="'$(MonoMsCorDbi)' == 'true'" Include="$(MonoObjDir)out\lib\$(LibPrefix)mscordbi$(LibSuffix)"> $(RuntimeBinDir)$(LibPrefix)mscordbi$(LibSuffix) diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index 884b43c1b1eec4..5d6ef3dfa3c31e 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -288,7 +288,6 @@ set(interp_sources interp/interp.h interp/interp-internals.h interp/interp.c - interp/interp-simd.c interp/interp-intrins.h interp/interp-intrins.c interp/mintops.h @@ -297,11 +296,17 @@ set(interp_sources interp/tiering.h interp/tiering.c interp/jiterpreter.c) +set(interp_simd_sources + interp/interp-simd.c) set(interp_stub_sources interp-stubs.c) if(NOT DISABLE_INTERPRETER) -set(mini_interp_sources ${interp_sources}) + if(HOST_WASM) + set(mini_interp_sources ${interp_sources}) + else() + set(mini_interp_sources ${interp_sources} ${interp_simd_sources}) + endif() else() set(mini_interp_sources ${interp_stub_sources}) endif() @@ -504,6 +509,19 @@ if(HOST_BROWSER) install(TARGETS mono-wasm-eh-wasm LIBRARY) endif() +if(HOST_BROWSER OR HOST_WASI) + add_library(mono-wasm-simd STATIC interp/interp-simd.c) + target_link_libraries (mono-wasm-simd PRIVATE monoapi eglib_api) + set_target_properties(mono-wasm-simd PROPERTIES COMPILE_FLAGS "-msimd128") + install(TARGETS mono-wasm-simd LIBRARY) +endif() + +if(HOST_BROWSER OR HOST_WASI OR TARGET_WASM) + add_library(mono-wasm-nosimd STATIC interp/interp-nosimd.c) + target_link_libraries (mono-wasm-nosimd PRIVATE monoapi eglib_api) + install(TARGETS mono-wasm-nosimd LIBRARY) +endif() + find_package(Python3 COMPONENTS Interpreter) add_custom_command( @@ -576,6 +594,9 @@ if(NOT DISABLE_EXECUTABLES) endif() endif() target_link_libraries(mono-sgen PRIVATE monoapi eglib_api monosgen-static) + if (HOST_WASM) + target_link_libraries(mono-sgen PRIVATE mono-wasm-nosimd) + endif() if(HAVE_ICU_SHIM) target_link_libraries(mono-sgen PRIVATE icu_shim_objects) endif() diff --git a/src/mono/mono/mini/interp/interp-nosimd.c b/src/mono/mono/mini/interp/interp-nosimd.c new file mode 100644 index 00000000000000..63bcf2783ec087 --- /dev/null +++ b/src/mono/mono/mini/interp/interp-nosimd.c @@ -0,0 +1,31 @@ + +#include "interp-internals.h" +#include "interp-simd.h" + +#ifdef INTERP_ENABLE_SIMD + +gboolean interp_simd_enabled = FALSE; + +#ifdef HOST_BROWSER + +int interp_simd_p_p_wasm_opcode_table [] = { +}; + +int interp_simd_p_pp_wasm_opcode_table [] = { +}; + +int interp_simd_p_ppp_wasm_opcode_table [] = { +}; + +#endif // HOST_BROWSER + +PP_SIMD_Method interp_simd_p_p_table [] = { +}; + +PPP_SIMD_Method interp_simd_p_pp_table [] = { +}; + +PPPP_SIMD_Method interp_simd_p_ppp_table [] = { +}; + +#endif // INTERP_ENABLE_SIMD diff --git a/src/mono/mono/mini/interp/interp-simd.c b/src/mono/mono/mini/interp/interp-simd.c index 65e60b4c6e7017..5031c87aaf206b 100644 --- a/src/mono/mono/mini/interp/interp-simd.c +++ b/src/mono/mono/mini/interp/interp-simd.c @@ -8,6 +8,8 @@ #ifdef INTERP_ENABLE_SIMD +gboolean interp_simd_enabled = TRUE; + typedef gint64 v128_i8 __attribute__ ((vector_size (SIZEOF_V128))); typedef guint64 v128_u8 __attribute__ ((vector_size (SIZEOF_V128))); typedef gint32 v128_i4 __attribute__ ((vector_size (SIZEOF_V128))); diff --git a/src/mono/mono/mini/interp/interp-simd.h b/src/mono/mono/mini/interp/interp-simd.h index e3306a251fc9f6..8e0222613e44a2 100644 --- a/src/mono/mono/mini/interp/interp-simd.h +++ b/src/mono/mono/mini/interp/interp-simd.h @@ -3,6 +3,8 @@ #include +extern gboolean interp_simd_enabled; + typedef void (*PP_SIMD_Method) (gpointer, gpointer); typedef void (*PPP_SIMD_Method) (gpointer, gpointer, gpointer); typedef void (*PPPP_SIMD_Method) (gpointer, gpointer, gpointer, gpointer); diff --git a/src/mono/mono/mini/interp/transform-simd.c b/src/mono/mono/mini/interp/transform-simd.c index 255a2aba595634..7df7f92ab6d7c0 100644 --- a/src/mono/mono/mini/interp/transform-simd.c +++ b/src/mono/mono/mini/interp/transform-simd.c @@ -3,6 +3,7 @@ */ #include "config.h" +#include "interp-simd.h" #include #include #include @@ -900,6 +901,9 @@ interp_emit_simd_intrinsics (TransformData *td, MonoMethod *cmethod, MonoMethodS if (image != mono_get_corlib ()) return FALSE; + if (!interp_simd_enabled) + return FALSE; + class_ns = m_class_get_name_space (cmethod->klass); class_name = m_class_get_name (cmethod->klass); diff --git a/src/mono/wasi/build/WasiApp.Native.targets b/src/mono/wasi/build/WasiApp.Native.targets index 36c66585870a2c..ba9c085924d46a 100644 --- a/src/mono/wasi/build/WasiApp.Native.targets +++ b/src/mono/wasi/build/WasiApp.Native.targets @@ -273,6 +273,10 @@ <_WasmEHLibToExclude Condition="'$(WasmEnableExceptionHandling)' != 'true'">libmono-wasm-eh-wasm.a + <_WasmSIMDLib Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-simd.a + <_WasmSIMDLib Condition="'$(WasmEnableSIMD)' != 'true'">libmono-wasm-nosimd.a + <_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' != 'true'">libmono-wasm-simd.a + <_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-nosimd.a @@ -286,7 +290,9 @@ Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)*.a" Exclude="@(_MonoRuntimeComponentDontLink->'$(MicrosoftNetCoreAppRuntimePackRidNativeDir)%(Identity)')" /> <_WasmNativeFileForLinking Condition="'$(_WasmEHLib)' != ''" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmEHLib)" /> + <_WasmNativeFileForLinking Condition="'$(_WasmSIMDLib)' != ''" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmSIMDLib)" /> <_WasmNativeFileForLinking Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmEHLibToExclude)" /> + <_WasmNativeFileForLinking Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmSIMDLibToExclude)" /> <_WasmNativeFileForLinking Include="$(WasiSysRoot)\lib\wasm32-wasi\libc++.a" /> <_WasmNativeFileForLinking Include="$(WasiSysRoot)\lib\wasm32-wasi\libc++abi.a" /> diff --git a/src/mono/wasi/runtime/CMakeLists.txt b/src/mono/wasi/runtime/CMakeLists.txt index ede21d72193f6c..912132b06ccfb0 100644 --- a/src/mono/wasi/runtime/CMakeLists.txt +++ b/src/mono/wasi/runtime/CMakeLists.txt @@ -26,6 +26,7 @@ target_link_libraries(dotnet ${MONO_ARTIFACTS_DIR}/libmono-ee-interp.a ${MONO_ARTIFACTS_DIR}/libmonosgen-2.0.a ${MONO_ARTIFACTS_DIR}/libmono-icall-table.a + ${MONO_ARTIFACTS_DIR}/libmono-wasm-${CONFIGURATION_INTERPSIMDTABLES_LIB}.a ${NATIVE_BIN_DIR}/wasm-bundled-timezones.a ${NATIVE_BIN_DIR}/libSystem.Native.a ${NATIVE_BIN_DIR}/libSystem.Globalization.Native.a diff --git a/src/mono/wasi/wasi.proj b/src/mono/wasi/wasi.proj index 611d7969f034b8..b942b6f4925035 100644 --- a/src/mono/wasi/wasi.proj +++ b/src/mono/wasi/wasi.proj @@ -218,6 +218,8 @@ $(CMakeBuildRuntimeConfigureCmd) -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" $(CMakeBuildRuntimeConfigureCmd) -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" $(CMakeBuildRuntimeConfigureCmd) -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" + $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_COMPILE_OPTIONS="-msimd128" -DCONFIGURATION_INTERPSIMDTABLES_LIB="simd" + $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_INTERPSIMDTABLES_LIB="nosimd" $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_THREADS=0 call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" wasm && $(CMakeBuildRuntimeConfigureCmd) diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 52125a8bd00b00..7060397f0cb85c 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -440,6 +440,10 @@ <_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' != 'true'">libmono-wasm-eh-js.a <_WasmEHLibToExclude Condition="'$(WasmEnableExceptionHandling)' == 'true'">libmono-wasm-eh-js.a <_WasmEHLibToExclude Condition="'$(WasmEnableExceptionHandling)' != 'true'">libmono-wasm-eh-wasm.a + <_WasmSIMDLib Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-simd.a + <_WasmSIMDLib Condition="'$(WasmEnableSIMD)' != 'true'">libmono-wasm-nosimd.a + <_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' != 'true'">libmono-wasm-simd.a + <_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-nosimd.a <_EmccExportedLibraryFunction>"[@(EmccExportedLibraryFunction -> '%27%(Identity)%27', ',')]" <_EmccExportedRuntimeMethods>"[@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]" <_EmccExportedFunctions>@(EmccExportedFunction -> '%(Identity)',',') @@ -460,7 +464,9 @@ Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)*.a" Exclude="@(_MonoRuntimeComponentDontLink->'$(MicrosoftNetCoreAppRuntimePackRidNativeDir)%(Identity)')" /> <_WasmNativeFileForLinking Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmEHLib)" /> + <_WasmNativeFileForLinking Condition="'$(_WasmSIMDLib)' != ''" Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmSIMDLib)" /> <_WasmNativeFileForLinking Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmEHLibToExclude)" /> + <_WasmNativeFileForLinking Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(_WasmSIMDLibToExclude)" /> <_WasmExtraJSFile Include="@(Content)" Condition="'%(Content.Extension)' == '.js'" /> diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 6b8ef873ec27da..6d939088d74314 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(dotnet.native ${MONO_ARTIFACTS_DIR}/libmonosgen-2.0.a ${MONO_ARTIFACTS_DIR}/libmono-icall-table.a ${MONO_ARTIFACTS_DIR}/libmono-wasm-eh-js.a + ${MONO_ARTIFACTS_DIR}/libmono-wasm-${CONFIGURATION_INTERPSIMDTABLES_LIB}.a ${MONO_ARTIFACTS_DIR}/libmono-profiler-aot.a ${MONO_ARTIFACTS_DIR}/libmono-profiler-browser.a ${NATIVE_BIN_DIR}/wasm-bundled-timezones.a diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index c46c92ab70db70..66bc509910571a 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -388,7 +388,8 @@ $(CMakeBuildRuntimeConfigureCmd) -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/').Replace('\','/'))" $(CMakeBuildRuntimeConfigureCmd) -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/').Replace('\','/'))" $(CMakeBuildRuntimeConfigureCmd) -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/').Replace('\','/'))" - $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_COMPILE_OPTIONS="-msimd128" + $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_COMPILE_OPTIONS="-msimd128" -DCONFIGURATION_INTERPSIMDTABLES_LIB="simd" + $(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_INTERPSIMDTABLES_LIB="nosimd" $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_THREADS=0 $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_LEGACY_JS_INTEROP=1 $(CMakeBuildRuntimeConfigureCmd) $(CMakeConfigurationEmsdkPath) From 92d1962d546e60172d69ecfda9e8c34123896732 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 13:04:51 -0700 Subject: [PATCH 042/345] Disable BinderTracingTest.ResolutionFlow test (#90818) Tracking: #90580 Co-authored-by: Bruce Forstall --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 87f8bbf2673dd3..22178e4b3b506d 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -63,6 +63,9 @@ https://github.com/dotnet/runtime/issues/57786 + + https://github.com/dotnet/runtime/issues/90580 + CoreCLR does not implement the mono embedding API From 90b92bb265a412592c4c152983d7b30c92236dbe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 17:06:10 -0700 Subject: [PATCH 043/345] run nightlies against release/8.0 (#90809) Co-authored-by: antonfirsov --- eng/pipelines/libraries/stress/http.yml | 1 + eng/pipelines/libraries/stress/ssl.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/eng/pipelines/libraries/stress/http.yml b/eng/pipelines/libraries/stress/http.yml index 6c740e49d04d47..f4f9c45de36e48 100644 --- a/eng/pipelines/libraries/stress/http.yml +++ b/eng/pipelines/libraries/stress/http.yml @@ -13,6 +13,7 @@ schedules: - main - release/6.0 - release/7.0 + - release/8.0 variables: - template: ../variables.yml diff --git a/eng/pipelines/libraries/stress/ssl.yml b/eng/pipelines/libraries/stress/ssl.yml index 791251030f5753..ab93994400d346 100644 --- a/eng/pipelines/libraries/stress/ssl.yml +++ b/eng/pipelines/libraries/stress/ssl.yml @@ -13,6 +13,7 @@ schedules: - main - release/6.0 - release/7.0 + - release/8.0 variables: - template: ../variables.yml From f8e2a9b9beccddae9f0838dd7a1bdcc3f994777e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 18:17:18 -0700 Subject: [PATCH 044/345] Enable telemetry for WasmStripILAfterAOT (#90827) Co-authored-by: Fan Yang --- .../WorkloadTelemetry.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets index 8f78ce16b62587..cf97ec1f14c2af 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadTelemetry.targets @@ -19,6 +19,7 @@ + @@ -35,6 +36,7 @@ <_WorkloadUsesInterpreter Condition="'$(_WorkloadUsesInterpreter)' == '' and '$(UseInterpreter)' == 'true'">true <_WorkloadUsesInterpreter Condition="'$(_WorkloadUsesInterpreter)' == '' and '$(RunAOTCompilation)' != 'true' and ('$(_WorkloadUsesBlazorWasm)' == 'true' or '$(_WorkloadUsesWasmSDK)' == 'true')">true <_WorkloadUsesLibraryMode Condition="'$(NativeLib)' != '' and ('$(_WorkloadUsesMonoAOT)' == 'true' or '$(_WorkloadUsesNativeAOT)' == 'true')">true + <_WorkloadUsesWasmStripILAfterAOT Condition="'$(WasmStripILAfterAOT)' == 'true'">true From 6aef01d5aae9dc0cd88c876a642cb06e4fcaafc4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 19:33:12 -0700 Subject: [PATCH 045/345] [release/8.0-rc1] [mini] Fix typo in mono_decompose_vtype_opts (#90832) * Fix typo in mono_decompose_vtype_opts Without this, if some previous instruction already created a vreg for ins->dest (for example if we are doing multiple passes over the basic block because `restart == TRUE`) we will use an incorrect vreg when decomposing the current VMOVE Fixes https://github.com/dotnet/runtime/issues/90800 * Only emit an OP_LDTOKEN_FIELD if we loaded a field token This is used by a CreateSpan optimization that needs access to the MonoClassField* For other cases of a bare LDTOKEN (such as hand-written IL that calls LDTOKEN on a type but doesn't follow it up with a call to `GetTypeFromHandle` leave the opcode as a VMOVE (from the `EMIT_NEW_TEMPLOAD` above)) --------- Co-authored-by: Aleksey Kliger --- src/mono/mono/mini/decompose.c | 2 +- src/mono/mono/mini/method-to-ir.c | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/decompose.c b/src/mono/mono/mini/decompose.c index b4570cc0c7429d..2be1ff52e416d0 100644 --- a/src/mono/mono/mini/decompose.c +++ b/src/mono/mono/mini/decompose.c @@ -1226,7 +1226,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg) dest_var = get_vreg_to_inst (cfg, ins->dreg); if (!src_var) - src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg); + src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1); if (!dest_var) dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index b5f75ea1c3133d..e3605981bafcdf 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -10840,12 +10840,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0); MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg); EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0); - ins->opcode = OP_LDTOKEN_FIELD; - ins->inst_c0 = n; - ins->inst_p1 = handle; + if (handle_class == mono_defaults.fieldhandle_class) { + ins->opcode = OP_LDTOKEN_FIELD; + ins->inst_c0 = n; + ins->inst_p1 = handle; + + cfg->flags |= MONO_CFG_NEEDS_DECOMPOSE; + cfg->cbb->needs_decompose = TRUE; + } - cfg->flags |= MONO_CFG_NEEDS_DECOMPOSE; - cfg->cbb->needs_decompose = TRUE; } } From 034d27f4a9420e10601447d0385c88de9b4a2925 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 19 Aug 2023 09:13:47 -0700 Subject: [PATCH 046/345] [release/8.0-rc1] Use Roslyn interceptors feature in binder gen (#90835) * Use Roslyn interceptors feature in binder gen * Fix polymorphic issue and address feedback * Fix source build issue * Revert changes to options gen * Fix * Work around source build issue Co-authored-by: Eric StJohn --------- Co-authored-by: Layomi Akinrinade Co-authored-by: Eric StJohn --- docs/project/list-of-diagnostics.md | 2 + eng/SourceBuildPrebuiltBaseline.xml | 1 + .../ConfigurationBindingGenerator.Emitter.cs | 87 +++---- .../ConfigurationBindingGenerator.Parser.cs | 69 ++++-- ...onfigurationBindingGenerator.Suppressor.cs | 70 ++++++ .../gen/ConfigurationBindingGenerator.cs | 12 +- .../Helpers/Emitter/ConfigurationBinder.cs | 146 ++++++------ ...BindingHelper.cs => CoreBindingHelpers.cs} | 215 ++++++++---------- .../gen/Helpers/Emitter/Helpers.cs | 159 ++++++------- .../OptionsBuilderConfigurationExtensions.cs | 44 ++-- ...onfigurationServiceCollectionExtensions.cs | 49 ++-- .../gen/Helpers/InterceptorLocationInfo.cs | 90 ++++++++ .../gen/Helpers/MethodsToGen.cs | 9 +- .../gen/Helpers/Parser/BinderInvocation.cs | 2 +- .../gen/Helpers/Parser/ConfigurationBinder.cs | 33 ++- .../OptionsBuilderConfigurationExtensions.cs | 44 ++-- ...onfigurationServiceCollectionExtensions.cs | 4 +- ...nfiguration.Binder.SourceGeneration.csproj | 6 +- .../gen/Model/ObjectSpec.cs | 4 - .../gen/Model/ParsableFromStringSpec.cs | 2 +- .../gen/Model/SourceGenerationSpec.cs | 8 +- .../gen/Model/TypeSpec.cs | 9 +- .../gen/Resources/Strings.resx | 4 +- .../gen/Resources/xlf/Strings.cs.xlf | 8 +- .../gen/Resources/xlf/Strings.de.xlf | 8 +- .../gen/Resources/xlf/Strings.es.xlf | 8 +- .../gen/Resources/xlf/Strings.fr.xlf | 8 +- .../gen/Resources/xlf/Strings.it.xlf | 8 +- .../gen/Resources/xlf/Strings.ja.xlf | 8 +- .../gen/Resources/xlf/Strings.ko.xlf | 8 +- .../gen/Resources/xlf/Strings.pl.xlf | 8 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 8 +- .../gen/Resources/xlf/Strings.ru.xlf | 8 +- .../gen/Resources/xlf/Strings.tr.xlf | 8 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 8 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 8 +- .../tests/Common/ConfigurationBinderTests.cs | 3 +- .../Baselines/Collections.generated.txt | 79 ++----- .../ConfigurationBinder/Bind.generated.txt | 100 +++++--- .../Bind_Instance.generated.txt | 60 +++-- .../Bind_Instance_BinderOptions.generated.txt | 62 ++--- .../Bind_Key_Instance.generated.txt | 60 +++-- .../ConfigurationBinder/Get.generated.txt | 81 +++---- .../GetValue.generated.txt | 57 +++-- .../GetValue_T_Key.generated.txt | 29 ++- .../GetValue_T_Key_DefaultValue.generated.txt | 29 ++- .../GetValue_TypeOf_Key.generated.txt | 29 ++- ...alue_TypeOf_Key_DefaultValue.generated.txt | 29 ++- .../ConfigurationBinder/Get_T.generated.txt | 54 ++--- .../Get_T_BinderOptions.generated.txt | 54 ++--- .../Get_TypeOf.generated.txt | 39 ++-- .../Get_TypeOf_BinderOptions.generated.txt | 39 ++-- .../BindConfiguration.generated.txt | 96 +++++--- .../OptionsBuilder/Bind_T.generated.txt | 117 +++++----- .../Bind_T_BinderOptions.generated.txt | 105 +++++---- .../Baselines/Primitives.generated.txt | 45 +++- .../Configure_T.generated.txt | 101 ++++---- .../Configure_T_BinderOptions.generated.txt | 101 ++++---- .../Configure_T_name.generated.txt | 101 ++++---- ...nfigure_T_name_BinderOptions.generated.txt | 91 ++++---- ...BindingGeneratorTests.Baselines.Options.cs | 4 + ...gurationBindingGeneratorTests.Baselines.cs | 4 +- .../ConfigurationBindingGeneratorTests.cs | 18 +- ...ation.Binder.SourceGeneration.Tests.csproj | 2 +- ...ft.Extensions.Logging.Configuration.csproj | 1 + ...icrosoft.Extensions.Logging.Console.csproj | 2 + ...onExtensions.SourceGeneration.Tests.csproj | 4 +- 67 files changed, 1581 insertions(+), 1188 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/{CoreBindingHelper.cs => CoreBindingHelpers.cs} (83%) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 4f78e9e711653d..579b8d160d59b0 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -270,3 +270,5 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | Suppression ID | Suppressed Diagnostic ID | Description | | :----------------------- | :----------------------- | :---------- | | __`SYSLIBSUPPRESS0001`__ | CA1822 | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. | +| __`SYSLIBSUPPRESS0002`__ | IL2026 | ConfigurationBindingGenerator: suppress RequiresUnreferencedCode diagnostic for binding call that has been intercepted by a generated static variant. | +| __`SYSLIBSUPPRESS0003`__ | IL3050 | ConfigurationBindingGenerator: suppress RequiresDynamicCode diagnostic for binding call that has been intercepted by a generated static variant. | diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml index 74f6be96543a5e..46dd7457d764aa 100644 --- a/eng/SourceBuildPrebuiltBaseline.xml +++ b/eng/SourceBuildPrebuiltBaseline.xml @@ -10,6 +10,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs index a40cf2976b31fc..756e10bc26b8d5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Immutable; using System.Diagnostics; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; @@ -17,7 +18,6 @@ private sealed partial class Emitter private readonly SourceGenerationSpec _sourceGenSpec; private bool _emitBlankLineBeforeNextStatement; - private bool _useFullyQualifiedNames; private int _valueSuffixIndex; private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]")); @@ -32,7 +32,7 @@ public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSp public void Emit() { - if (!ShouldEmitBinders()) + if (!ShouldEmitBindingExtensions()) { return; } @@ -42,17 +42,26 @@ public void Emit() #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. """); - _writer.WriteLine(); - _useFullyQualifiedNames = true; - EmitBinder_Extensions_IConfiguration(); - EmitBinder_Extensions_OptionsBuilder(); - EmitBinder_Extensions_IServiceCollection(); + EmitInterceptsLocationAttrDecl(); + + EmitStartBlock($"namespace {ProjectName}"); + EmitUsingStatements(); + + _writer.WriteLine(); + EmitStartBlock($$""" + {{Expression.GeneratedCodeAnnotation}} + file static class {{Identifier.BindingExtensions}} + """); + EmitBindingExtensions_IConfiguration(); + EmitBindingExtensions_OptionsBuilder(); + EmitBindingExtensions_IServiceCollection(); + EmitCoreBindingHelpers(); + EmitEndBlock(); // BindingExtensions class - _useFullyQualifiedNames = false; - Emit_CoreBindingHelper(); + EmitEndBlock(); // Binding namespace. - _context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", _writer.ToSourceText()); + _context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText()); } private void EmitBindCoreCall( @@ -74,7 +83,7 @@ private void EmitBindCoreCall( if (initKind is InitializationKind.AssignmentWithNullCheck) { Debug.Assert(!type.IsValueType); - _writer.WriteLine($"{type.MinimalDisplayString}? {tempIdentifier} = {memberAccessExpr};"); + _writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};"); EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck); } else if (initKind is InitializationKind.None && type.IsValueType) @@ -89,9 +98,7 @@ private void EmitBindCoreCall( void EmitBindCoreCall(string objExpression, InitializationKind initKind) { - string methodDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCore)); - string bindCoreCall = $@"{methodDisplayString}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});"; - + string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});"; EmitObjectInit(objExpression, initKind); _writer.WriteLine(bindCoreCall); writeOnSuccess?.Invoke(objExpression); @@ -127,12 +134,11 @@ private void EmitBindLogicFromString( } else if (typeKind is StringParsableTypeKind.Enum) { - parsedValueExpr = $"ParseEnum<{type.MinimalDisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})"; + parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})"; } else { - string helperMethodDisplayString = GetHelperMethodDisplayString(type.ParseMethodName); - parsedValueExpr = $"{helperMethodDisplayString}({stringValueToParse_Expr}, () => {sectionPathExpr})"; + parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})"; } if (!checkForNullSectionValue) @@ -156,7 +162,7 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati string initExpr; CollectionSpec? collectionType = type as CollectionSpec; - string effectiveDisplayString = GetTypeDisplayString(type); + string effectiveDisplayString = type.DisplayString; if (collectionType is not null) { if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array }) @@ -165,7 +171,7 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati } else { - effectiveDisplayString = GetTypeDisplayString(collectionType.ConcreteType ?? collectionType); + effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString; initExpr = $"new {effectiveDisplayString}()"; } } @@ -215,36 +221,41 @@ private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, Initializati return true; } - private void EmitCastToIConfigurationSection() + private void EmitInterceptsLocationAttrDecl() { - string sectionTypeDisplayString; - string exceptionTypeDisplayString; - if (_useFullyQualifiedNames) - { - sectionTypeDisplayString = "global::Microsoft.Extensions.Configuration.IConfigurationSection"; - exceptionTypeDisplayString = FullyQualifiedDisplayString.InvalidOperationException; - } - else - { - sectionTypeDisplayString = Identifier.IConfigurationSection; - exceptionTypeDisplayString = nameof(InvalidOperationException); - } - + _writer.WriteLine(); _writer.WriteLine($$""" - if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}}) + namespace System.Runtime.CompilerServices { - throw new {{exceptionTypeDisplayString}}(); + using System; + using System.CodeDom.Compiler; + + {{Expression.GeneratedCodeAnnotation}} + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } """); + _writer.WriteLine(); + } + + private void EmitUsingStatements() + { + foreach (string @namespace in _sourceGenSpec.Namespaces.ToImmutableSortedSet()) + { + _writer.WriteLine($"using {@namespace};"); + } } private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn) { string returnPostfix = voidReturn ? string.Empty : " null"; - string methodDisplayString = GetHelperMethodDisplayString(Identifier.HasValueOrChildren); - _writer.WriteLine($$""" - if (!{{methodDisplayString}}({{Identifier.configuration}})) + if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}})) { return{{returnPostfix}}; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index b0f53ef074078f..64db4eb58b1f77 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -1,12 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -147,7 +149,7 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || { // List is used in generated code as a temp holder for formatting // an error for config properties that don't map to object properties. - _sourceGenSpec.TypeNamespaces.Add("System.Collections.Generic"); + _sourceGenSpec.Namespaces.Add("System.Collections.Generic"); spec = CreateObjectSpec(namedType); } @@ -169,32 +171,54 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || string @namespace = spec.Namespace; if (@namespace is not null and not "") { - _sourceGenSpec.TypeNamespaces.Add(@namespace); + _sourceGenSpec.Namespaces.Add(@namespace); } return _createdSpecs[type] = spec; } - private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type) + private void RegisterTypeForBindCoreMainGen(TypeSpec typeSpec) { - if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet? types)) + if (typeSpec.NeedsMemberBinding) { - _sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet(); + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec); + RegisterTypeForBindCoreGen(typeSpec); + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; } - - types.Add(type); - _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method; } - private void RegisterTypeForBindCoreUntypedGen(TypeSpec typeSpec) + private void RegisterTypeForBindCoreGen(TypeSpec typeSpec) { if (typeSpec.NeedsMemberBinding) { RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec); - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreUntyped, typeSpec); } } + private void RegisterTypeForGetCoreGen(TypeSpec typeSpec) + { + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec); + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + } + + private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type) + { + if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet? types)) + { + _sourceGenSpec.TypesForGen_CoreBindingHelper_Methods[method] = types = new HashSet(); + } + + types.Add(type); + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method; + } + + /// + /// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind, + /// which is handled by + /// + private void RegisterAsInterceptor(Enum method, IInvocationOperation operation) => + _sourceGenSpec.InterceptionInfo.RegisterCacheEntry(method, new InterceptorLocationInfo(operation)); + private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType) { if (type is INamedTypeSymbol { IsGenericType: true } genericType && @@ -335,7 +359,7 @@ private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, o // We want a BindCore method for List as a temp holder for the array values. We know the element type is supported. EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!; - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, listSpec); + RegisterTypeForBindCoreGen(listSpec); EnumerableSpec spec = new EnumerableSpec(arrayType) { @@ -347,7 +371,7 @@ private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, o }; Debug.Assert(spec.CanInitialize); - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec); + RegisterTypeForBindCoreGen(spec); return spec; } @@ -383,7 +407,7 @@ private bool IsSupportedArrayType(ITypeSymbol type) if (spec is not null) { - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec); + RegisterTypeForBindCoreGen(spec); spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage; } @@ -442,7 +466,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k constructionStrategy = InitializationStrategy.ToEnumerableMethod; populationStrategy = CollectionPopulationStrategy.Cast_Then_Add; toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)"; - _sourceGenSpec.TypeNamespaces.Add("System.Linq"); + _sourceGenSpec.Namespaces.Add("System.Linq"); } else { @@ -711,7 +735,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k if (objectSpec.NeedsMemberBinding) { - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, objectSpec); + RegisterTypeForBindCoreGen(objectSpec); } return objectSpec; @@ -890,4 +914,19 @@ private void RegisterTypeDiagnostic(ITypeSymbol causingType, InvocationDiagnosti } } } + + public static class ParserExtensions + { + public static void RegisterCacheEntry(this Dictionary cache, TKey key, TEntry entry) + where TKey : notnull + where TValue : ICollection, new() + { + if (!cache.TryGetValue(key, out TValue? entryCollection)) + { + cache[key] = entryCollection = new TValue(); + } + + entryCollection.Add(entry); + } + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs new file mode 100644 index 00000000000000..13158753c3f075 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Suppressor.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + public sealed partial class ConfigurationBindingGenerator + { + /// + /// Supresses false-positive diagnostics emitted by the linker + /// when analyzing binding invocations that we have intercepted. + /// Workaround for https://github.com/dotnet/roslyn/issues/68669. + /// + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class Suppressor : DiagnosticSuppressor + { + private const string Justification = "The target method has been intercepted by a generated static variant."; + + /// + /// Suppression descriptor for IL2026: Members attributed with RequiresUnreferencedCode may break when trimming. + /// + private static readonly SuppressionDescriptor RUCDiagnostic = new(id: "SYSLIBSUPPRESS0002", suppressedDiagnosticId: "IL2026", Justification); + + /// + /// Suppression descriptor for IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as native AOT. + /// + private static readonly SuppressionDescriptor RDCDiagnostic = new(id: "SYSLIBSUPPRESS0003", suppressedDiagnosticId: "IL3050", Justification); + + public override ImmutableArray SupportedSuppressions => ImmutableArray.Create(RUCDiagnostic, RDCDiagnostic); + + public override void ReportSuppressions(SuppressionAnalysisContext context) + { + foreach (Diagnostic diagnostic in context.ReportedDiagnostics) + { + string diagnosticId = diagnostic.Id; + + if (diagnosticId != RDCDiagnostic.SuppressedDiagnosticId && diagnosticId != RUCDiagnostic.SuppressedDiagnosticId) + { + continue; + } + + Location location = diagnostic.AdditionalLocations.Count > 0 + ? diagnostic.AdditionalLocations[0] + : diagnostic.Location; + + bool shouldSuppressDiagnostic = + location.SourceTree is SyntaxTree sourceTree && + sourceTree.GetRoot().FindNode(location.SourceSpan) is SyntaxNode syntaxNode && + BinderInvocation.IsCandidateSyntaxNode(syntaxNode) && + context.GetSemanticModel(sourceTree) + .GetOperation((InvocationExpressionSyntax)syntaxNode, context.CancellationToken) is IInvocationOperation operation && + BinderInvocation.IsBindingOperation(operation); + + if (shouldSuppressDiagnostic) + { + SuppressionDescriptor targetSuppression = diagnosticId == RUCDiagnostic.SuppressedDiagnosticId + ? RUCDiagnostic + : RDCDiagnostic; + context.ReportSuppression(Suppression.Create(targetSuppression, diagnostic)); + } + } + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs index 70da582dddf0cd..fbca2dd3cfc507 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.cs @@ -5,7 +5,6 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [Generator] public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator { - internal const string ProjectName = "Microsoft.Extensions.Configuration.Binder.SourceGeneration"; + private static readonly string ProjectName = Emitter.s_assemblyName.Name; public void Initialize(IncrementalGeneratorInitializationContext context) { @@ -42,9 +41,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context) context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc)); } - /// - /// Generates source code to optimize binding with ConfigurationBinder. - /// private static void Execute(CompilationData compilationData, ImmutableArray inputCalls, SourceProductionContext context) { if (inputCalls.IsDefaultOrEmpty) @@ -73,7 +69,11 @@ private sealed record CompilationData public CompilationData(CSharpCompilation compilation) { - LanguageVersionIsSupported = compilation.LanguageVersion >= LanguageVersion.CSharp11; + // We don't have a CSharp21 value available yet. Polyfill the value here for forward compat, rather than use the LangugeVersion.Preview enum value. + // https://github.com/dotnet/roslyn/blob/168689931cb4e3150641ec2fb188a64ce4b3b790/src/Compilers/CSharp/Portable/LanguageVersion.cs#L218-L232 + const int LangVersion_CSharp12 = 1200; + LanguageVersionIsSupported = (int)compilation.LanguageVersion >= LangVersion_CSharp12; + if (LanguageVersionIsSupported) { TypeSymbols = new KnownTypeSymbols(compilation); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs index c10e607df75d0a..64064887c7c70b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -14,91 +12,84 @@ private sealed partial class Emitter { private bool ShouldEmitMethods(MethodsToGen_ConfigurationBinder methods) => (_sourceGenSpec.MethodsToGen_ConfigurationBinder & methods) != 0; - private void EmitBinder_Extensions_IConfiguration() + private void EmitBindingExtensions_IConfiguration() { - Debug.Assert(_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Count <= 3 && - !_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Keys.Any(overload => (overload & MethodsToGen_ConfigurationBinder.Bind) is 0)); - if (!ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any)) { return; } - _emitBlankLineBeforeNextStatement = false; - EmitRootBindingClassStartBlock(Identifier.GeneratedConfigurationBinder); - + EmitBindingExtStartRegion(Identifier.IConfiguration); EmitGetMethods(); EmitGetValueMethods(); EmitBindMethods_ConfigurationBinder(); - - EmitEndBlock(); - _emitBlankLineBeforeNextStatement = true; + EmitBindingExtEndRegion(); } private void EmitGetMethods() { - const string expressionForGetCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetCore)}"; + const string expressionForGetCore = nameof(MethodsToGen_CoreBindingHelper.GetCore); const string documentation = "Attempts to bind the configuration instance to a new instance of type T."; if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static T? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T, documentation); + _writer.WriteLine($"public static T? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}) => " + $"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}: null) ?? default(T));"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static T? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions, documentation); + _writer.WriteLine($"public static T? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " + $"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}) ?? default(T));"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf, documentation); + _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}) => " + $"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions}: null);"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions, documentation); + _writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " + $"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions});"); } } private void EmitGetValueMethods() { - const string expressionForGetValueCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}"; + const string expressionForGetValueCore = $"{Identifier.BindingExtensions}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}"; const string documentation = "Extracts the value with the specified key and converts it to the specified type."; if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static T? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key, documentation); + _writer.WriteLine($"public static T? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " + $"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? default(T));"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static T? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue, documentation); + _writer.WriteLine($"public static T? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " + $"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? {Identifier.defaultValue});"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key, documentation); + _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}) => " + $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key});"); } if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue)) { - StartMethodDefinition(documentation); - _writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " + + StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue, documentation); + _writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " + $"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key}) ?? {Identifier.defaultValue};"); } } @@ -110,72 +101,71 @@ private void EmitBindMethods_ConfigurationBinder() return; } - Dictionary> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods; + string objParamExpr = $"object? {Identifier.obj}"; - if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance, out HashSet? typeSpecs)) + if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance)) { - foreach (TypeSpec type in typeSpecs) - { - EmitMethodImplementation( - type, - additionalParams: GetObjParameter(type), - configExpression: Identifier.configuration, - configureOptions: false); - } + EmitMethods( + MethodsToGen_ConfigurationBinder.Bind_instance, + additionalParams: objParamExpr, + configExpression: Identifier.configuration, + configureOptions: false); } - if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, out typeSpecs)) + if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions)) { - foreach (TypeSpec type in typeSpecs) - { - EmitMethodImplementation( - type, - additionalParams: $"{GetObjParameter(type)}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}", - configExpression: Identifier.configuration, - configureOptions: true); - } + EmitMethods( + MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, + additionalParams: $"{objParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}", + configExpression: Identifier.configuration, + configureOptions: true); } - if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_key_instance, out typeSpecs)) + if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_key_instance)) { - foreach (TypeSpec type in typeSpecs) - { - EmitMethodImplementation( - type, - additionalParams: $"string {Identifier.key}, {GetObjParameter(type)}", - configExpression: $"{Expression.configurationGetSection}({Identifier.key})", - configureOptions: false); - } + EmitMethods( + MethodsToGen_ConfigurationBinder.Bind_key_instance, + additionalParams: $"string {Identifier.key}, {objParamExpr}", + configExpression: $"{Expression.configurationGetSection}({Identifier.key})", + configureOptions: false); } - void EmitMethodImplementation(TypeSpec type, string additionalParams, string configExpression, bool configureOptions) + void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions) { - string binderOptionsArg = configureOptions ? $"{Expression.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null"; - - string returnExpression; - if (type.CanInitialize) + foreach (KeyValuePair> pair in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method)) { - returnExpression = type.NeedsMemberBinding - ? $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configExpression}, ref {Identifier.obj}, {binderOptionsArg})" - : "{ }"; + (TypeSpec type, List interceptorInfoList) = (pair.Key, pair.Value); + + EmitBlankLineIfRequired(); + _writer.WriteLine($"/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively."); + EmitInterceptsLocationAnnotations(interceptorInfoList); + EmitStartBlock($"public static void {Identifier.Bind}_{type.DisplayString.ToIdentifierSubstring()}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})"); + + if (!EmitInitException(type) && type.NeedsMemberBinding) + { + string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null"; + + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); + if (!type.IsValueType) + { + EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + } + _writer.WriteLine($$""" + var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.obj}}; + {{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, {{binderOptionsArg}}); + """); + } + + EmitEndBlock(); } - else - { - returnExpression = GetInitException(type.InitExceptionMessage); - } - - StartMethodDefinition("Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively."); - _writer.WriteLine($"public static void {Identifier.Bind}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {additionalParams}) => " - + $"{returnExpression};"); } - - string GetObjParameter(TypeSpec type) => $"{type.FullyQualifiedDisplayString} {Identifier.obj}"; } - private void StartMethodDefinition(string documentation) + private void StartMethodDefinition(MethodsToGen_ConfigurationBinder method, string documentation) { EmitBlankLineIfRequired(); _writer.WriteLine($"/// {documentation}"); + EmitInterceptsLocationAnnotations(method); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs similarity index 83% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs index a7b42b1329804e..f30408fad596dd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs @@ -3,10 +3,10 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -16,41 +16,18 @@ private sealed partial class Emitter { private bool ShouldEmitMethods(MethodsToGen_CoreBindingHelper methods) => (_sourceGenSpec.MethodsToGen_CoreBindingHelper & methods) != 0; - private void Emit_CoreBindingHelper() + private void EmitCoreBindingHelpers() { Debug.Assert(_emitBlankLineBeforeNextStatement); - _writer.WriteLine(); - _emitBlankLineBeforeNextStatement = false; - - EmitStartBlock($"namespace {ProjectName}"); - EmitHelperUsingStatements(); - - _writer.WriteLine(); - - EmitStartBlock($$""" - /// Provide core binding logic. - {{GetGeneratedCodeAttributeSrc()}} - file static class {{Identifier.CoreBindingHelper}} - """); - + EmitBindingExtStartRegion("Core binding"); EmitConfigurationKeyCaches(); EmitGetCoreMethod(); EmitGetValueCoreMethod(); - EmitBindCoreUntypedMethod(); + EmitBindCoreMainMethod(); EmitBindCoreMethods(); EmitInitializeMethods(); EmitHelperMethods(); - - EmitEndBlock(); // End helper class. - EmitEndBlock(); // End namespace. - } - - private void EmitHelperUsingStatements() - { - foreach (string @namespace in _sourceGenSpec.TypeNamespaces.ToImmutableSortedSet()) - { - _writer.WriteLine($"using {@namespace};"); - } + EmitBindingExtEndRegion(); } private void EmitConfigurationKeyCaches() @@ -60,6 +37,8 @@ private void EmitConfigurationKeyCaches() return; } + EmitBlankLineIfRequired(); + foreach (TypeSpec type in targetTypes) { if (type is not ObjectSpec objectType) @@ -73,10 +52,8 @@ private void EmitConfigurationKeyCaches() string configKeysSource = string.Join(", ", keys); string fieldName = GetConfigKeyCacheFieldName(objectType); - _writer.WriteLine($@"private readonly static Lazy<{MinimalDisplayString.HashSetOfString}> {fieldName} = new(() => new {MinimalDisplayString.HashSetOfString}(StringComparer.OrdinalIgnoreCase) {{ {configKeysSource} }});"); + _writer.WriteLine($@"private readonly static Lazy<{TypeDisplayString.HashSetOfString}> {fieldName} = new(() => new {TypeDisplayString.HashSetOfString}(StringComparer.OrdinalIgnoreCase) {{ {configKeysSource} }});"); } - - _emitBlankLineBeforeNextStatement = true; } private void EmitGetCoreMethod() @@ -96,16 +73,24 @@ private void EmitGetCoreMethod() EmitIConfigurationHasValueOrChildrenCheck(voidReturn: false); + bool isFirstType = true; foreach (TypeSpec type in types) { TypeSpec effectiveType = type.EffectiveType; TypeSpecKind kind = effectiveType.SpecKind; + string conditionKindExpr = GetConditionKindExpr(ref isFirstType); - EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))"); + EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); if (effectiveType is ParsableFromStringSpec stringParsableType) { - EmitCastToIConfigurationSection(); + _writer.WriteLine($$""" + if ({{Identifier.configuration}} is not {{Identifier.IConfigurationSection}} {{Identifier.section}}) + { + throw new {{Identifier.InvalidOperationException}}(); + } + """); + EmitBindLogicFromString( stringParsableType, Expression.sectionValue, @@ -121,9 +106,9 @@ private void EmitGetCoreMethod() } EmitEndBlock(); - _writer.WriteLine(); } + _writer.WriteLine(); Emit_NotSupportedException_TypeNotDetectedAsInput(); EmitEndBlock(); _emitBlankLineBeforeNextStatement = true; @@ -152,9 +137,11 @@ private void EmitGetValueCoreMethod() _writer.WriteLine(); + bool isFirstType = true; foreach (TypeSpec type in targetTypes) { - EmitStartBlock($"if ({Identifier.type} == typeof({type.MinimalDisplayString}))"); + string conditionKindExpr = GetConditionKindExpr(ref isFirstType); + EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); EmitBindLogicFromString( (ParsableFromStringSpec)type.EffectiveType, @@ -165,51 +152,48 @@ private void EmitGetValueCoreMethod() useIncrementalStringValueIdentifier: false); EmitEndBlock(); - _writer.WriteLine(); } + _writer.WriteLine(); _writer.WriteLine("return null;"); EmitEndBlock(); _emitBlankLineBeforeNextStatement = true; } - private void EmitBindCoreUntypedMethod() + private void EmitBindCoreMainMethod() { - if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreUntyped, out HashSet? targetTypes)) + if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreMain, out HashSet? targetTypes)) { return; } EmitBlankLineIfRequired(); - - EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}(this {Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {MinimalDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); - + EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); - + EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true); _writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});"); _writer.WriteLine(); - EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true); - + bool isFirstType = true; foreach (TypeSpec type in targetTypes) { - EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))"); - TypeSpec effectiveType = type.EffectiveType; + string conditionKindExpr = GetConditionKindExpr(ref isFirstType); + + EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); if (!EmitInitException(effectiveType)) { - _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.MinimalDisplayString}){Identifier.obj};"); + _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.obj};"); EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None); _writer.WriteLine($"return;"); } - EmitEndBlock(); - _writer.WriteLine(); } + _writer.WriteLine(); Emit_NotSupportedException_TypeNotDetectedAsInput(); EmitEndBlock(); - _emitBlankLineBeforeNextStatement = true; } private void EmitBindCoreMethods() @@ -231,11 +215,9 @@ private void EmitBindCoreMethod(TypeSpec type) { Debug.Assert(type.CanInitialize); - string objParameterExpression = $"ref {type.MinimalDisplayString} {Identifier.obj}"; + string objParameterExpression = $"ref {type.DisplayString} {Identifier.obj}"; EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})"); - EmitCheckForNullArgument_WithBlankLine_IfRequired(type.IsValueType); - TypeSpec effectiveType = type.EffectiveType; if (effectiveType is EnumerableSpec enumerable) { @@ -281,9 +263,9 @@ private void EmitInitializeMethod(ObjectSpec type) List ctorParams = type.ConstructorParameters; IEnumerable initOnlyProps = type.Properties.Values.Where(prop => prop is { SetOnInit: true }); List ctorArgList = new(); - string displayString = type.MinimalDisplayString; + string displayString = type.DisplayString; - EmitStartBlock($"public static {type.MinimalDisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})"); + EmitStartBlock($"public static {type.DisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})"); _emitBlankLineBeforeNextStatement = false; foreach (ParameterSpec parameter in ctorParams) @@ -335,7 +317,7 @@ void EmitBindImplForMember(MemberSpec member) TypeSpec memberType = member.Type; bool errorOnFailedBinding = member.ErrorOnFailedBinding; - string parsedMemberIdentifierDeclarationPrefix = $"{memberType.MinimalDisplayString} {member.Name}"; + string parsedMemberIdentifierDeclarationPrefix = $"{memberType.DisplayString} {member.Name}"; string parsedMemberIdentifier; if (memberType is ParsableFromStringSpec { StringParsableTypeKind: StringParsableTypeKind.AssignFromSectionValue }) @@ -344,7 +326,7 @@ void EmitBindImplForMember(MemberSpec member) if (errorOnFailedBinding) { - string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.MinimalDisplayString} {member.Name})"; + string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.DisplayString} {member.Name})"; EmitThrowBlock(condition); _writer.WriteLine(); return; @@ -393,40 +375,42 @@ void EmitThrowBlock(string condition) => _writer.WriteLine($$""" {{condition}} { - throw new {{GetInvalidOperationDisplayName()}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}"); + throw new {{Identifier.InvalidOperationException}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}"); } """); } } + private void EmitHelperMethods() { + // Emitted if we are to bind objects with complex members, or if we're emitting BindCoreMain or GetCore methods. + bool emitAsConfigWithChildren = ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren); + if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore)) { + EmitBlankLineIfRequired(); EmitValidateConfigurationKeysMethod(); } - if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore)) + if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore)) { - _writer.WriteLine(); + // HasValueOrChildren references this method. + Debug.Assert(emitAsConfigWithChildren); + EmitBlankLineIfRequired(); EmitHasValueOrChildrenMethod(); - _writer.WriteLine(); - EmitAsConfigWithChildrenMethod(); - _emitBlankLineBeforeNextStatement = true; } - else if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren)) + + if (emitAsConfigWithChildren) { - _writer.WriteLine(); + EmitBlankLineIfRequired(); EmitAsConfigWithChildrenMethod(); - _emitBlankLineBeforeNextStatement = true; } - if (ShouldEmitMethods( - MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore) || + if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore) || ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions)) { - _writer.WriteLine(); + EmitBlankLineIfRequired(); EmitGetBinderOptionsHelper(); - _emitBlankLineBeforeNextStatement = true; } bool enumTypeExists = false; @@ -458,17 +442,17 @@ private void EmitValidateConfigurationKeysMethod() EmitBlankLineIfRequired(); _writer.WriteLine($$""" /// If required by the binder options, validates that there are no unknown keys in the input configuration object. - public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{MinimalDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}}) + public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{TypeDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}}) { if ({{Identifier.binderOptions}}?.{{Identifier.ErrorOnUnknownConfiguration}} is true) { - {{MinimalDisplayString.ListOfString}}? {{Identifier.temp}} = null; + {{TypeDisplayString.ListOfString}}? {{Identifier.temp}} = null; foreach ({{Identifier.IConfigurationSection}} {{Identifier.section}} in {{Identifier.configuration}}.{{Identifier.GetChildren}}()) { if (!{{keysIdentifier}}.Value.Contains({{Expression.sectionKey}})) { - ({{Identifier.temp}} ??= new {{MinimalDisplayString.ListOfString}}()).Add($"'{{{Expression.sectionKey}}}'"); + ({{Identifier.temp}} ??= new {{TypeDisplayString.ListOfString}}()).Add($"'{{{Expression.sectionKey}}}'"); } } @@ -490,7 +474,7 @@ private void EmitHasValueOrChildrenMethod() { return true; } - return {{Identifier.AsConfigWithChildren}}({{Identifier.configuration}}) is not null; + return {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.configuration}}) is not null; } """); } @@ -498,7 +482,7 @@ private void EmitHasValueOrChildrenMethod() private void EmitAsConfigWithChildrenMethod() { _writer.WriteLine($$""" - public static {{Identifier.IConfiguration}}? {{Identifier.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) + public static {{Identifier.IConfiguration}}? {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}}) { foreach ({{Identifier.IConfigurationSection}} _ in {{Identifier.configuration}}.{{Identifier.GetChildren}}()) { @@ -512,7 +496,7 @@ private void EmitAsConfigWithChildrenMethod() private void EmitGetBinderOptionsHelper() { _writer.WriteLine($$""" - public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{MinimalDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}}) + public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{TypeDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}}) { if ({{Identifier.configureOptions}} is null) { @@ -524,7 +508,7 @@ private void EmitGetBinderOptionsHelper() if ({{Identifier.binderOptions}}.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"{{string.Format(ExceptionMessages.CannotSpecifyBindNonPublicProperties)}}"); + throw new NotSupportedException($"{{string.Format(ExceptionMessages.CannotSpecifyBindNonPublicProperties)}}"); } return {{Identifier.binderOptions}}; @@ -534,7 +518,6 @@ private void EmitGetBinderOptionsHelper() private void EmitEnumParseMethod() { - string innerExceptionTypeDisplayString = _useFullyQualifiedNames ? "global::System.Exception" : "Exception"; string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}"); _writer.WriteLine($$""" @@ -548,9 +531,9 @@ public static T ParseEnum(string value, Func getPath) where T : stru return Enum.Parse(value, ignoreCase: true); #endif } - catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}}) + catch ({{Identifier.Exception}} {{Identifier.exception}}) { - throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}}); + throw new {{Identifier.InvalidOperationException}}($"{{exceptionArg1}}", {{Identifier.exception}}); } } """); @@ -558,29 +541,12 @@ public static T ParseEnum(string value, Func getPath) where T : stru private void EmitPrimitiveParseMethod(ParsableFromStringSpec type) { - string innerExceptionTypeDisplayString; - string cultureInfoTypeDisplayString; - string numberStylesTypeDisplayString; - - if (_useFullyQualifiedNames) - { - innerExceptionTypeDisplayString = "global::System.Exception"; - cultureInfoTypeDisplayString = "global::System.Globalization.CultureInfo"; - numberStylesTypeDisplayString = "global::System.Globalization.NumberStyles"; - } - else - { - innerExceptionTypeDisplayString = "Exception"; - cultureInfoTypeDisplayString = "CultureInfo"; - numberStylesTypeDisplayString = "NumberStyles"; - } - StringParsableTypeKind typeKind = type.StringParsableTypeKind; - string typeDisplayString = type.MinimalDisplayString; - - string invariantCultureExpression = $"{cultureInfoTypeDisplayString}.InvariantCulture"; + string typeDisplayString = type.DisplayString; + string invariantCultureExpression = $"{Identifier.CultureInfo}.InvariantCulture"; string parsedValueExpr; + switch (typeKind) { case StringParsableTypeKind.Enum: @@ -592,12 +558,12 @@ private void EmitPrimitiveParseMethod(ParsableFromStringSpec type) break; case StringParsableTypeKind.Integer: { - parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {numberStylesTypeDisplayString}.Integer, {invariantCultureExpression})"; + parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {Identifier.NumberStyles}.Integer, {invariantCultureExpression})"; } break; case StringParsableTypeKind.Float: { - parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {numberStylesTypeDisplayString}.Float, {invariantCultureExpression})"; + parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {Identifier.NumberStyles}.Float, {invariantCultureExpression})"; } break; case StringParsableTypeKind.Parse: @@ -612,7 +578,7 @@ private void EmitPrimitiveParseMethod(ParsableFromStringSpec type) break; case StringParsableTypeKind.CultureInfo: { - parsedValueExpr = $"{cultureInfoTypeDisplayString}.GetCultureInfo({Identifier.value})"; + parsedValueExpr = $"{Identifier.CultureInfo}.GetCultureInfo({Identifier.value})"; } break; case StringParsableTypeKind.Uri: @@ -635,9 +601,9 @@ private void EmitPrimitiveParseMethod(ParsableFromStringSpec type) { return {{parsedValueExpr}}; } - catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}}) + catch ({{Identifier.Exception}} {{Identifier.exception}}) { - throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}}); + throw new {{Identifier.InvalidOperationException}}($"{{exceptionArg1}}", {{Identifier.exception}}); } """); } @@ -722,13 +688,13 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) if (keyType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue) { // Save value to local to avoid parsing twice - during look-up and during add. - _writer.WriteLine($"{keyType.MinimalDisplayString} {Identifier.key} = {parsedKeyExpr};"); + _writer.WriteLine($"{keyType.DisplayString} {Identifier.key} = {parsedKeyExpr};"); parsedKeyExpr = Identifier.key; } bool isValueType = elementType.IsValueType; string expressionForElementIsNotNull = $"{Identifier.element} is not null"; - string elementTypeDisplayString = elementType.MinimalDisplayString + (elementType.IsValueType ? string.Empty : "?"); + string elementTypeDisplayString = elementType.DisplayString + (elementType.IsValueType ? string.Empty : "?"); string expressionForElementExists = $"{objIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})"; string conditionToUseExistingElement = expressionForElementExists; @@ -749,7 +715,7 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) // we need to copy its contents into a new instance & then append/bind to that. string initExpression = collectionSpec.InitializationStrategy is InitializationStrategy.ParameterizedConstructor - ? $"new {collectionSpec.ConcreteType.MinimalDisplayString}({Identifier.element})" + ? $"new {collectionSpec.ConcreteType.DisplayString}({Identifier.element})" : $"{Identifier.element}.{collectionSpec.ToEnumerableMethodCall!}"; _writer.WriteLine($$""" @@ -773,7 +739,7 @@ private void EmitBindCoreImplForObject(ObjectSpec type) Debug.Assert(type.NeedsMemberBinding); string keyCacheFieldName = GetConfigKeyCacheFieldName(type); - string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.MinimalDisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});"; + string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.DisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});"; _writer.WriteLine(validateMethodCallExpr); foreach (PropertySpec property in type.Properties.Values) @@ -781,7 +747,7 @@ private void EmitBindCoreImplForObject(ObjectSpec type) bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor }; if (property.ShouldBind() && !noSetter_And_IsReadonly) { - string containingTypeRef = property.IsStatic ? type.MinimalDisplayString : Identifier.obj; + string containingTypeRef = property.IsStatic ? type.DisplayString : Identifier.obj; EmitBindImplForMember( property, memberAccessExpr: $"{containingTypeRef}.{property.Name}", @@ -832,7 +798,7 @@ private bool EmitBindImplForMember( return true; } - string sectionValidationCall = $"{Identifier.AsConfigWithChildren}({sectionParseExpr})"; + string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})"; string sectionIdentifier = GetIncrementalIdentifier(Identifier.section); EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})"); @@ -869,14 +835,14 @@ private void EmitBindCoreCallForMember( } Debug.Assert(canSet); - string effectiveMemberTypeDisplayString = effectiveMemberType.MinimalDisplayString; + string effectiveMemberTypeDisplayString = effectiveMemberType.DisplayString; initKind = InitializationKind.None; if (memberType.SpecKind is TypeSpecKind.Nullable) { string nullableTempIdentifier = GetIncrementalIdentifier(Identifier.temp); - _writer.WriteLine($"{memberType.MinimalDisplayString} {nullableTempIdentifier} = {memberAccessExpr};"); + _writer.WriteLine($"{memberType.DisplayString} {nullableTempIdentifier} = {memberAccessExpr};"); _writer.WriteLine( $"{effectiveMemberTypeDisplayString} {tempIdentifier} = {nullableTempIdentifier}.{Identifier.HasValue} ? {nullableTempIdentifier}.{Identifier.Value} : new {effectiveMemberTypeDisplayString}();"); @@ -924,7 +890,7 @@ private void EmitCollectionCastIfRequired(CollectionSpec type, out string objIde { objIdentifier = Identifier.temp; _writer.WriteLine($$""" - if ({{Identifier.obj}} is not {{type.PopulationCastType!.MinimalDisplayString}} {{objIdentifier}}) + if ({{Identifier.obj}} is not {{type.PopulationCastType!.DisplayString}} {{objIdentifier}}) { return; } @@ -936,20 +902,31 @@ private void EmitCollectionCastIfRequired(CollectionSpec type, out string objIde private void Emit_Foreach_Section_In_ConfigChildren_StartBlock() => EmitStartBlock($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())"); + private void Emit_NotSupportedException_TypeNotDetectedAsInput() => + _writer.WriteLine(@$"throw new NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");"); + private static string GetSectionPathFromConfigurationExpression(string configurationKeyName) => $@"{GetSectionFromConfigurationExpression(configurationKeyName)}.{Identifier.Path}"; private static string GetSectionFromConfigurationExpression(string configurationKeyName, bool addQuotes = true) { string argExpr = addQuotes ? $@"""{configurationKeyName}""" : configurationKeyName; - return $@"{Expression.configurationGetSection}({argExpr})"; + return $@"{Identifier.configuration}.{Identifier.GetSection}({argExpr})"; } - private static string GetConfigKeyCacheFieldName(ObjectSpec type) => - $"s_configKeys_{type.DisplayStringWithoutSpecialCharacters}"; + private static string GetConditionKindExpr(ref bool isFirstType) + { + if (isFirstType) + { + isFirstType = false; + return "if"; + } - private void Emit_NotSupportedException_TypeNotDetectedAsInput() => - _writer.WriteLine(@$"throw new global::System.NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");"); + return "else if"; + } + + private static string GetConfigKeyCacheFieldName(ObjectSpec type) => + $"s_configKeys_{type.DisplayString.ToIdentifierSubstring()}"; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index e0e6a36aabaa7c..bad56b7ce3275a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Reflection; @@ -10,7 +12,9 @@ public sealed partial class ConfigurationBindingGenerator { private sealed partial class Emitter { - private static readonly AssemblyName s_assemblyName = typeof(Emitter).Assembly.GetName(); + private string? _emittedExtsTargetType; + + internal static readonly AssemblyName s_assemblyName = typeof(ConfigurationBindingGenerator).Assembly.GetName(); private enum InitializationKind { @@ -26,29 +30,13 @@ private static class Expression public const string sectionPath = "section.Path"; public const string sectionValue = "section.Value"; - public const string GetBinderOptions = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{Identifier.GetBinderOptions}"; - } - - private static class FullyQualifiedDisplayString - { - public const string ActionOfBinderOptions = $"global::System.Action"; - public const string AddSingleton = $"{ServiceCollectionServiceExtensions}.AddSingleton"; - public const string ConfigurationChangeTokenSource = "global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource"; - public const string CoreBindingHelper = $"global::{ProjectName}.{Identifier.CoreBindingHelper}"; - public const string IConfiguration = "global::Microsoft.Extensions.Configuration.IConfiguration"; - public const string IConfigurationSection = IConfiguration + "Section"; - public const string IOptionsChangeTokenSource = "global::Microsoft.Extensions.Options.IOptionsChangeTokenSource"; - public const string InvalidOperationException = "global::System.InvalidOperationException"; - public const string IServiceCollection = "global::Microsoft.Extensions.DependencyInjection.IServiceCollection"; - public const string NotSupportedException = "global::System.NotSupportedException"; - public const string OptionsBuilderOfTOptions = $"global::Microsoft.Extensions.Options.OptionsBuilder<{Identifier.TOptions}>"; - public const string ServiceCollectionServiceExtensions = "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions"; - public const string Type = $"global::System.Type"; + public static string GeneratedCodeAnnotation = $@"[GeneratedCode(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]"; } - private static class MinimalDisplayString + private static class TypeDisplayString { public const string NullableActionOfBinderOptions = "Action?"; + public const string OptionsBuilderOfTOptions = $"OptionsBuilder<{Identifier.TOptions}>"; public const string HashSetOfString = "HashSet"; public const string LazyHashSetOfString = "Lazy>"; public const string ListOfString = "List"; @@ -75,6 +63,7 @@ private static class Identifier public const string services = nameof(services); public const string temp = nameof(temp); public const string type = nameof(type); + public const string typedObj = nameof(typedObj); public const string validateKeys = nameof(validateKeys); public const string value = nameof(value); @@ -82,21 +71,19 @@ private static class Identifier public const string AddSingleton = nameof(AddSingleton); public const string Any = nameof(Any); public const string Array = nameof(Array); - public const string AsConfigWithChildren = nameof(AsConfigWithChildren); public const string Bind = nameof(Bind); public const string BinderOptions = nameof(BinderOptions); + public const string BindingExtensions = nameof(BindingExtensions); + public const string ConfigurationChangeTokenSource = nameof(ConfigurationChangeTokenSource); public const string Configure = nameof(Configure); public const string CopyTo = nameof(CopyTo); public const string ContainsKey = nameof(ContainsKey); - public const string CoreBindingHelper = nameof(CoreBindingHelper); public const string Count = nameof(Count); public const string CultureInfo = nameof(CultureInfo); public const string CultureNotFoundException = nameof(CultureNotFoundException); public const string Enum = nameof(Enum); public const string ErrorOnUnknownConfiguration = nameof(ErrorOnUnknownConfiguration); - public const string GeneratedConfigurationBinder = nameof(GeneratedConfigurationBinder); - public const string GeneratedOptionsBuilderBinder = nameof(GeneratedOptionsBuilderBinder); - public const string GeneratedServiceCollectionBinder = nameof(GeneratedServiceCollectionBinder); + public const string Exception = nameof(Exception); public const string Get = nameof(Get); public const string GetBinderOptions = nameof(GetBinderOptions); public const string GetChildren = nameof(GetChildren); @@ -108,9 +95,13 @@ private static class Identifier public const string IConfiguration = nameof(IConfiguration); public const string IConfigurationSection = nameof(IConfigurationSection); public const string Int32 = "int"; + public const string InterceptsLocation = nameof(InterceptsLocation); public const string InvalidOperationException = nameof(InvalidOperationException); public const string InvariantCulture = nameof(InvariantCulture); + public const string IOptionsChangeTokenSource = nameof(IOptionsChangeTokenSource); + public const string IServiceCollection = nameof(IServiceCollection); public const string Length = nameof(Length); + public const string NumberStyles = nameof(NumberStyles); public const string Parse = nameof(Parse); public const string Path = nameof(Path); public const string Resize = nameof(Resize); @@ -118,17 +109,66 @@ private static class Identifier public const string TOptions = nameof(TOptions); public const string TryCreate = nameof(TryCreate); public const string TryGetValue = nameof(TryGetValue); - public const string TryParse = nameof(TryParse); + public const string Type = nameof(Type); public const string Uri = nameof(Uri); public const string ValidateConfigurationKeys = nameof(ValidateConfigurationKeys); public const string Value = nameof(Value); } - private bool ShouldEmitBinders() => + private bool ShouldEmitBindingExtensions() => ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any) || ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any) || ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any); + private void EmitInterceptsLocationAnnotations(Enum generatedBindingOverload) + { + // The only time a generated binding method won't have any locations to + // intercept is when either of these methods are used as helpers for + // other generated OptionsBuilder or ServiceCollection binding extensions. + bool interceptsCalls = _sourceGenSpec.InterceptionInfo.TryGetValue(generatedBindingOverload, out List? infoList); + Debug.Assert(interceptsCalls || + generatedBindingOverload is MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions || + generatedBindingOverload is MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions); + + if (interceptsCalls) + { + EmitInterceptsLocationAnnotations(infoList); + } + } + + private void EmitInterceptsLocationAnnotations(List infoList) + { + foreach (InterceptorLocationInfo info in infoList) + { + _writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); + } + } + + private void EmitBindingExtStartRegion(string targetType) + { + Debug.Assert(_emittedExtsTargetType is null); + + EmitBlankLineIfRequired(); + _emittedExtsTargetType = targetType; + EmitBindingExtRegionText(isStart: true); + _emitBlankLineBeforeNextStatement = false; + } + + private void EmitBindingExtEndRegion() + { + Debug.Assert(_emittedExtsTargetType is not null); + + EmitBindingExtRegionText(isStart: false); + _emittedExtsTargetType = null; + _emitBlankLineBeforeNextStatement = true; + } + + private void EmitBindingExtRegionText(bool isStart) + { + string endSource = isStart ? string.Empty : "end"; + _writer.WriteLine($"#{endSource}region {_emittedExtsTargetType} extensions."); + } + /// /// Starts a block of source code. /// @@ -171,24 +211,12 @@ private void EmitBlankLineIfRequired() _emitBlankLineBeforeNextStatement = true; } - private void EmitCheckForNullArgument_WithBlankLine_IfRequired(bool isValueType) - { - if (!isValueType) - { - EmitCheckForNullArgument_WithBlankLine(Identifier.obj); - } - } - private void EmitCheckForNullArgument_WithBlankLine(string paramName) { - string exceptionTypeDisplayString = _useFullyQualifiedNames - ? "global::System.ArgumentNullException" - : "ArgumentNullException"; - _writer.WriteLine($$""" if ({{paramName}} is null) { - throw new {{exceptionTypeDisplayString}}(nameof({{paramName}})); + throw new ArgumentNullException(nameof({{paramName}})); } """); @@ -201,51 +229,28 @@ private bool EmitInitException(TypeSpec type) if (!type.CanInitialize) { - _writer.WriteLine(GetInitException(type.InitExceptionMessage) + ";"); + _writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{type.InitExceptionMessage}"");"); return true; } return false; } - private void EmitRootBindingClassStartBlock(string className) - { - EmitBlankLineIfRequired(); - EmitStartBlock($$""" - /// Generated helper providing an AOT and linking compatible implementation for configuration binding. - {{GetGeneratedCodeAttributeSrc()}} - internal static class {{className}} - """); - - _emitBlankLineBeforeNextStatement = false; - } - - private string GetGeneratedCodeAttributeSrc() - { - string attributeRefExpr = _useFullyQualifiedNames ? $"global::System.CodeDom.Compiler.GeneratedCodeAttribute" : "GeneratedCode"; - return $@"[{attributeRefExpr}(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]"; - } - - private string GetInitException(string message) => $@"throw new {GetInvalidOperationDisplayName()}(""{message}"")"; - private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}"; - private string GetInitalizeMethodDisplayString(ObjectSpec type) => - GetHelperMethodDisplayString($"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayStringWithoutSpecialCharacters}"); - - private string GetTypeDisplayString(TypeSpec type) => _useFullyQualifiedNames ? type.FullyQualifiedDisplayString : type.MinimalDisplayString; - - private string GetHelperMethodDisplayString(string methodName) - { - if (_useFullyQualifiedNames) - { - methodName = FullyQualifiedDisplayString.CoreBindingHelper + "." + methodName; - } - - return methodName; - } - - private string GetInvalidOperationDisplayName() => _useFullyQualifiedNames ? FullyQualifiedDisplayString.InvalidOperationException : Identifier.InvalidOperationException; + private static string GetInitalizeMethodDisplayString(ObjectSpec type) => + $"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayString.ToIdentifierSubstring()}"; } } + + internal static class EmitterExtensions + { + public static string ToIdentifierSubstring(this string typeDisplayName) => + typeDisplayName + .Replace("[]", nameof(Array)) + .Replace(", ", string.Empty) + .Replace(".", string.Empty) + .Replace("<", string.Empty) + .Replace(">", string.Empty); + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs index 71d0b6989dd970..d49198196fd491 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs @@ -9,19 +9,17 @@ private sealed partial class Emitter { private bool ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder methods) => (_sourceGenSpec.MethodsToGen_OptionsBuilderExt & methods) != 0; - private void EmitBinder_Extensions_OptionsBuilder() + private void EmitBindingExtensions_OptionsBuilder() { if (!ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any)) { return; } - EmitRootBindingClassStartBlock(Identifier.GeneratedOptionsBuilderBinder); - + EmitBindingExtStartRegion(TypeDisplayString.OptionsBuilderOfTOptions); EmitBindMethods_Extensions_OptionsBuilder(); EmitBindConfigurationMethod(); - - EmitEndBlock(); + EmitBindingExtEndRegion(); } private void EmitBindMethods_Extensions_OptionsBuilder() @@ -32,24 +30,25 @@ private void EmitBindMethods_Extensions_OptionsBuilder() } const string documentation = @"/// Registers a configuration instance which will bind against."; - const string paramList = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}"; + const string paramList = $"{Identifier.IConfiguration} {Identifier.configuration}"; if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T)) { - EmitMethodStartBlock("Bind", paramList, documentation); - _writer.WriteLine($"return global::{Identifier.GeneratedOptionsBuilderBinder}.Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); + EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.Bind_T, "Bind", paramList, documentation); + _writer.WriteLine($"return Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); EmitEndBlock(); } EmitMethodStartBlock( + MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions, "Bind", - paramList + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}", + paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}", documentation); EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder); _writer.WriteLine($$""" - global::{{Identifier.GeneratedServiceCollectionBinder}}.{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}}); + {{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}}); return {{Identifier.optionsBuilder}}; """); @@ -63,19 +62,20 @@ private void EmitBindConfigurationMethod() return; } - const string documentation = $@"/// Registers the dependency injection container to bind against the obtained from the DI service provider."; - string paramList = $"string {Identifier.configSectionPath}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions} = null"; + const string documentation = $@"/// Registers the dependency injection container to bind against the obtained from the DI service provider."; + string paramList = $"string {Identifier.configSectionPath}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions} = null"; - EmitMethodStartBlock("BindConfiguration", paramList, documentation); + EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration, "BindConfiguration", paramList, documentation); EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder); EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath); - EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{FullyQualifiedDisplayString.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>"); - + EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>"); + EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); _writer.WriteLine($$""" - {{FullyQualifiedDisplayString.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, global::System.StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}}); - {{FullyQualifiedDisplayString.CoreBindingHelper}}.{{nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}); + {{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}}); + {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}); """); EmitEndBlock(endBraceTrailingSource: ");"); @@ -83,20 +83,20 @@ private void EmitBindConfigurationMethod() _writer.WriteLine(); _writer.WriteLine($$""" - {{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.optionsBuilder}}.{{Identifier.Services}}); + {{Identifier.optionsBuilder}}.{{Identifier.Services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>(); return {{Identifier.optionsBuilder}}; """); EmitEndBlock(); } - private void EmitMethodStartBlock(string methodName, string paramList, string documentation) + private void EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder method, string methodName, string paramList, string documentation) { - paramList = $"this {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}"; - + paramList = $"this {TypeDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}"; EmitBlankLineIfRequired(); _writer.WriteLine(documentation); - EmitStartBlock($"public static {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class"); + EmitInterceptsLocationAnnotations(method); + EmitStartBlock($"public static {TypeDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class"); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs index f4cd4800df1230..0348eb5047e970 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs @@ -9,71 +9,72 @@ private sealed partial class Emitter { private bool ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection methods) => (_sourceGenSpec.MethodsToGen_ServiceCollectionExt & methods) != 0; - private void EmitBinder_Extensions_IServiceCollection() + private void EmitBindingExtensions_IServiceCollection() { if (!ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any)) { return; } - EmitRootBindingClassStartBlock(Identifier.GeneratedServiceCollectionBinder); + EmitBindingExtStartRegion(Identifier.IServiceCollection); + EmitConfigureMethods(); + EmitBindingExtEndRegion(); + } + private void EmitConfigureMethods() + { const string defaultNameExpr = "string.Empty"; - const string configureMethodString = $"global::{Identifier.GeneratedServiceCollectionBinder}.{Identifier.Configure}"; - string configParam = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}"; + string configParam = $"{Identifier.IConfiguration} {Identifier.configuration}"; if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T)) { - EmitStartMethod(configParam); - _writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); + EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T, configParam); + _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); EmitEndBlock(); } if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_name)) { EmitStartMethod( + MethodsToGen_Extensions_ServiceCollection.Configure_T_name, paramList: $"string? {Identifier.name}, " + configParam); - _writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); + _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); EmitEndBlock(); } if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions)) { EmitStartMethod( - paramList: configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}"); - _writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});"); + MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions, + paramList: configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}"); + _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});"); EmitEndBlock(); } // Core Configure method that the other overloads call. // Like the others, it is public API that could be called directly by users. // So, it is always generated whenever a Configure overload is called. - string optionsNamespaceName = "global::Microsoft.Extensions.Options"; - string bindCoreUntypedDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)); + string optionsNamespaceName = "Microsoft.Extensions.Options"; - EmitStartMethod(paramList: $"string? {Identifier.name}, " + configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}"); + EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, paramList: $"string? {Identifier.name}, " + configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}"); EmitCheckForNullArgument_WithBlankLine(Identifier.services); EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); _writer.WriteLine($$""" - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}}); - {{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}})); - return {{FullyQualifiedDisplayString.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{bindCoreUntypedDisplayString}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}))); + OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}}); + {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}})); + return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}){{Identifier.configureOptions}}))); """); EmitEndBlock(); - - EmitEndBlock(); - _emitBlankLineBeforeNextStatement = true; } - private void EmitStartMethod(string paramList) + private void EmitStartMethod(MethodsToGen_Extensions_ServiceCollection overload, string paramList) { - paramList = $"this {FullyQualifiedDisplayString.IServiceCollection} {Identifier.services}, {paramList}"; + paramList = $"this {Identifier.IServiceCollection} {Identifier.services}, {paramList}"; EmitBlankLineIfRequired(); - EmitStartBlock($$""" - /// Registers a configuration instance which TOptions will bind against. - public static {{FullyQualifiedDisplayString.IServiceCollection}} {{Identifier.Configure}}<{{Identifier.TOptions}}>({{paramList}}) where {{Identifier.TOptions}} : class - """); + _writer.WriteLine("/// Registers a configuration instance which TOptions will bind against."); + EmitInterceptsLocationAnnotations(overload); + EmitStartBlock($"public static {Identifier.IServiceCollection} {Identifier.Configure}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class"); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs new file mode 100644 index 00000000000000..d1dc4f4afa7e7e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs @@ -0,0 +1,90 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections; +using System.Collections.Generic; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + internal sealed record InterceptorLocationInfo + { + public InterceptorLocationInfo(IInvocationOperation operation) + { + SyntaxNode operationSyntax = operation.Syntax; + TextSpan operationSpan = operationSyntax.Span; + SyntaxTree operationSyntaxTree = operationSyntax.SyntaxTree; + + FilePath = GetInterceptorFilePath(operationSyntaxTree, operation.SemanticModel?.Compilation.Options.SourceReferenceResolver); + + FileLinePositionSpan span = operationSyntaxTree.GetLineSpan(operationSpan); + LineNumber = span.StartLinePosition.Line + 1; + + // Calculate the character offset to the end of the binding invocation detected. + int invocationLength = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operationSyntax).Expression).Expression.Span.Length; + CharacterNumber = span.StartLinePosition.Character + invocationLength + 2; + } + + public string FilePath { get; } + public int LineNumber { get; } + public int CharacterNumber { get; } + + // Utilize the same logic used by the interceptors API for resolving the source mapped value of a path. + // https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064 + private static string GetInterceptorFilePath(SyntaxTree tree, SourceReferenceResolver? resolver) => + resolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath; + } + + internal sealed record ConfigurationBinderInterceptorInfo + { + private OverloadInterceptorInfo? _bind_Instance; + private OverloadInterceptorInfo? _bind_instance_BinderOptions; + private OverloadInterceptorInfo? _bind_key_instance; + + public void RegisterOverloadInfo(MethodsToGen_ConfigurationBinder overload, TypeSpec type, IInvocationOperation operation) + { + OverloadInterceptorInfo overloadInfo = DetermineOverload(overload, initIfNull: true); + overloadInfo.RegisterLocationInfo(type, operation); + } + + public OverloadInterceptorInfo GetOverloadInfo(MethodsToGen_ConfigurationBinder overload) => + DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentNullException(nameof(overload)); + + private OverloadInterceptorInfo? DetermineOverload(MethodsToGen_ConfigurationBinder overload, bool initIfNull) + { + return overload switch + { + MethodsToGen_ConfigurationBinder.Bind_instance => InitIfNull(ref _bind_Instance), + MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => InitIfNull(ref _bind_instance_BinderOptions), + MethodsToGen_ConfigurationBinder.Bind_key_instance => InitIfNull(ref _bind_key_instance), + _ => throw new InvalidOperationException(nameof(overload)), + }; + + OverloadInterceptorInfo InitIfNull(ref OverloadInterceptorInfo? info) + { + if (initIfNull) + { + info ??= new OverloadInterceptorInfo(); + } + + return info; + } + } + } + + internal sealed record OverloadInterceptorInfo : IEnumerable>> + { + private readonly Dictionary> _typeInterceptionInfo = new(); + + public void RegisterLocationInfo(TypeSpec type, IInvocationOperation operation) => + _typeInterceptionInfo.RegisterCacheEntry(type, new InterceptorLocationInfo(operation)); + + public IEnumerator>> GetEnumerator() => _typeInterceptionInfo.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs index 7b40f198e08f23..2c582b20e8ebd6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs @@ -10,11 +10,12 @@ public enum MethodsToGen_CoreBindingHelper { None = 0x0, BindCore = 0x1, - BindCoreUntyped = 0x2, - GetCore = 0x4, - GetValueCore = 0x8, + GetCore = 0x2, + GetValueCore = 0x4, + BindCoreMain = 0x8, Initialize = 0x10, - AsConfigWithChildren = 0x20, + HasValueOrChildren = 0x20, + AsConfigWithChildren = 0x40, } /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs index 554786589c8c81..ad7c4c09204d4b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs @@ -40,7 +40,7 @@ static bool IsCandidateBindingMethodName(string name) => IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name); } - private static bool IsBindingOperation(IInvocationOperation operation) + public static bool IsBindingOperation(IInvocationOperation operation) { if (operation.TargetMethod is not IMethodSymbol { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs index a663c441c55ce3..e24ce11fe4374c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs @@ -102,15 +102,7 @@ private void RegisterBindInvocation(BinderInvocation invocation) if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) { - Dictionary> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods; - - if (!types.TryGetValue(overload, out HashSet? typeSpecs)) - { - types[overload] = typeSpecs = new HashSet(); - } - - _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; - typeSpecs.Add(typeSpec); + RegisterAsInterceptor_ConfigBinder_BindMethod(overload, typeSpec, invocation.Operation); } static ITypeSymbol? ResolveType(IOperation conversionOperation) => @@ -184,8 +176,8 @@ private void RegisterGetInvocation(BinderInvocation invocation) if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec) { - _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec); + RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation); + RegisterTypeForGetCoreGen(typeSpec); } } @@ -253,10 +245,27 @@ private void RegisterGetValueInvocation(BinderInvocation invocation) if (IsParsableFromString(effectiveType, out _) && GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) { - _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; + RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation); RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec); } } + + private void RegisterAsInterceptor_ConfigBinder(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation) + { + _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; + RegisterAsInterceptor(overload, operation); + } + + /// + /// Registers generated Bind methods as interceptors. This is done differently from other root + /// methods because we need to + /// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects. + /// + private void RegisterAsInterceptor_ConfigBinder_BindMethod(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation) + { + _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; + _sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation); + } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs index d01e80d708ca11..a62e63c0d90d5e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs @@ -34,9 +34,6 @@ private void RegisterMethodInvocation_OptionsBuilderExt(BinderInvocation invocat return; } - // We are going to emit calls to APIs on IServiceCollection. - _sourceGenSpec.TypeNamespaces.Add("Microsoft.Extensions.DependencyInjection"); - if (targetMethod.Name is "Bind") { RegisterBindInvocation(invocation, typeSpec); @@ -61,20 +58,19 @@ private void RegisterBindInvocation(BinderInvocation invocation, TypeSpec typeSp return; } - if (paramCount is 2) - { - _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T; - } - else if (paramCount is 3 && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type)) + MethodsToGen_Extensions_OptionsBuilder overload = paramCount switch { - _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions; - } - else + 2 => MethodsToGen_Extensions_OptionsBuilder.Bind_T, + 3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) => + MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions, + _ => MethodsToGen_Extensions_OptionsBuilder.None + }; + + if (overload is not MethodsToGen_Extensions_OptionsBuilder.None) { - return; + RegisterAsInterceptor_OptionsBuilder(overload, operation); + RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec); } - - RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec); } private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeSpec typeSpec) @@ -85,12 +81,26 @@ private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeS int paramCount = @params.Length; Debug.Assert(paramCount >= 2); - if (paramCount is 3 && @params[1].Type.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type)) + if (paramCount is 3 && + @params[1].Type.SpecialType is SpecialType.System_String && + SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type)) { - _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions; - RegisterTypeForBindCoreUntypedGen(typeSpec); + RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation); + RegisterTypeForBindCoreMainGen(typeSpec); } } + + private void RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation) + { + _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload; + RegisterAsInterceptor(overload, operation); + + // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource. + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); + + // Emitting refs to OptionsBuilder. + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); + } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs index 02c75b4ab653b3..c356b29a69efff 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -79,12 +79,14 @@ @params[1].Type.SpecialType is SpecialType.System_String && } RegisterTypeForMethodGen(overload, typeSpec); + RegisterAsInterceptor(overload, operation); } private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec) { _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; - RegisterTypeForBindCoreUntypedGen(typeSpec); + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); + RegisterTypeForBindCoreMainGen(typeSpec); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index 785a18c5c0978e..5b10a6f8e06c6b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -11,6 +11,8 @@ + + @@ -26,12 +28,14 @@ + - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs index 1696ee099fe469..8cc0ba68b49381 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs @@ -22,10 +22,6 @@ public ObjectSpec(INamedTypeSymbol type) : base(type) { } public List ConstructorParameters { get; } = new(); - private string _displayStringWithoutSpecialCharacters; - public string DisplayStringWithoutSpecialCharacters => - _displayStringWithoutSpecialCharacters ??= $"{MinimalDisplayString.Replace(".", string.Empty).Replace("<", string.Empty).Replace(">", string.Empty)}"; - public override bool NeedsMemberBinding => CanInitialize && Properties.Values.Count > 0 && Properties.Values.Any(p => p.ShouldBind()); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs index 6b5bb5b61ea371..e19e3e61d210f3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs @@ -24,7 +24,7 @@ public string ParseMethodName _parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray ? "ParseByteArray" // MinimalDisplayString.Length is certainly > 2. - : $"Parse{(char.ToUpper(MinimalDisplayString[0]) + MinimalDisplayString.Substring(1)).Replace(".", "")}"; + : $"Parse{(char.ToUpper(DisplayString[0]) + DisplayString.Substring(1)).Replace(".", "")}"; return _parseMethodName; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs index 88c4b24f57a5ea..760d57b1dcc888 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs @@ -1,21 +1,25 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal sealed record SourceGenerationSpec { + public Dictionary> InterceptionInfo { get; } = new(); + public ConfigurationBinderInterceptorInfo InterceptionInfo_ConfigBinder { get; } = new(); + public Dictionary> TypesForGen_CoreBindingHelper_Methods { get; } = new(); - public Dictionary> TypesForGen_ConfigurationBinder_BindMethods { get; } = new(); public HashSet PrimitivesForHelperGen { get; } = new(); - public HashSet TypeNamespaces { get; } = new() + public HashSet Namespaces { get; } = new() { "System", "System.CodeDom.Compiler", "System.Globalization", + "System.Runtime.CompilerServices", "Microsoft.Extensions.Configuration", }; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs index 6a6292b7ebd0b4..6f5e26bf3f6d38 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs @@ -17,17 +17,14 @@ public TypeSpec(ITypeSymbol type) { IsValueType = type.IsValueType; Namespace = type.ContainingNamespace?.ToDisplayString(); - FullyQualifiedDisplayString = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - MinimalDisplayString = type.ToDisplayString(s_minimalDisplayFormat); - Name = Namespace + "." + MinimalDisplayString.Replace(".", "+"); + DisplayString = type.ToDisplayString(s_minimalDisplayFormat); + Name = Namespace + "." + DisplayString.Replace(".", "+"); IsInterface = type.TypeKind is TypeKind.Interface; } public string Name { get; } - public string FullyQualifiedDisplayString { get; } - - public string MinimalDisplayString { get; } + public string DisplayString { get; } public string? Namespace { get; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx index 301913987d7c7e..3978cbaac6ce48 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx @@ -133,10 +133,10 @@ The collection element type is not supported: '{0}'. - The project's language version has to be at least 'C# 11'. + The project's language version has to be at least 'C# 12'. - Language version is required to be at least C# 11 + Language version is required to be at least C# 12 Cannot create instance of type '{0}' because it is missing a public instance constructor. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf index e248c54626865f..c6672eaff0bcd8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Jazyková verze projektu musí být alespoň C# 11 + The project's language version has to be at least 'C# 12'. + Jazyková verze projektu musí být alespoň C# 11 - Language version is required to be at least C# 11 - Verze jazyka musí být alespoň C# 11 + Language version is required to be at least C# 12 + Verze jazyka musí být alespoň C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf index 1fa847592bd02e..5f353065a5f511 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Die Sprachversion des Projekts muss mindestens „C# 11“ sein + The project's language version has to be at least 'C# 12'. + Die Sprachversion des Projekts muss mindestens „C# 11“ sein - Language version is required to be at least C# 11 - Die Sprachversion muss mindestens C# 11 sein + Language version is required to be at least C# 12 + Die Sprachversion muss mindestens C# 11 sein diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf index c52b2317ceaded..cd54149e66c2fa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - La versión del lenguaje del proyecto debe ser al menos "C# 11". + The project's language version has to be at least 'C# 12'. + La versión del lenguaje del proyecto debe ser al menos "C# 11". - Language version is required to be at least C# 11 - La versión del lenguaje debe ser al menos C# 11 + Language version is required to be at least C# 12 + La versión del lenguaje debe ser al menos C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf index 19362d7336208f..b1c0753a49e8a5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - La version de langage du projet doit être au moins « C# 11 ». + The project's language version has to be at least 'C# 12'. + La version de langage du projet doit être au moins « C# 11 ». - Language version is required to be at least C# 11 - La version du langage doit être au moins C# 11 + Language version is required to be at least C# 12 + La version du langage doit être au moins C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf index f418a83d0d422e..27d10a7ee5f9f2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - La versione del linguaggio del progetto deve essere almeno 'C# 11'. + The project's language version has to be at least 'C# 12'. + La versione del linguaggio del progetto deve essere almeno 'C# 11'. - Language version is required to be at least C# 11 - La versione del linguaggio deve essere almeno C# 11 + Language version is required to be at least C# 12 + La versione del linguaggio deve essere almeno C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf index ba59cfba40a89b..24621bcc8b3d22 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。 + The project's language version has to be at least 'C# 12'. + プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。 - Language version is required to be at least C# 11 - 言語バージョンは少なくとも C# 11 である必要があります + Language version is required to be at least C# 12 + 言語バージョンは少なくとも C# 11 である必要があります diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf index 10b9b107c4aade..217a0cd9f8e54c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - 프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다. + The project's language version has to be at least 'C# 12'. + 프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다. - Language version is required to be at least C# 11 - 언어 버전은 C# 11 이상이어야 합니다. + Language version is required to be at least C# 12 + 언어 버전은 C# 11 이상이어야 합니다. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf index 2b558c588ebfb9..0b24813a77a805 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Wersja językowa projektu musi mieć wartość co najmniej „C# 11”. + The project's language version has to be at least 'C# 12'. + Wersja językowa projektu musi mieć wartość co najmniej „C# 11”. - Language version is required to be at least C# 11 - Wymagana jest wersja językowa co najmniej C# 11 + Language version is required to be at least C# 12 + Wymagana jest wersja językowa co najmniej C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf index 9d2a51c6aa9c96..0ad700e64e9ebd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - A versão do idioma do projeto deve ser no mínimo 'C# 11'. + The project's language version has to be at least 'C# 12'. + A versão do idioma do projeto deve ser no mínimo 'C# 11'. - Language version is required to be at least C# 11 - A versão do idioma deve ser pelo menos C# 11 + Language version is required to be at least C# 12 + A versão do idioma deve ser pelo menos C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf index 1ed03c55891a9e..5e53330060c30b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Версия языка проекта должна быть не ниже "C# 11". + The project's language version has to be at least 'C# 12'. + Версия языка проекта должна быть не ниже "C# 11". - Language version is required to be at least C# 11 - Версия языка должна быть не ниже C# 11 + Language version is required to be at least C# 12 + Версия языка должна быть не ниже C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf index 8a6dbf76bab7f7..cfaea488fd195d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - Projenin dil sürümü en az 'C# 11' olmalıdır. + The project's language version has to be at least 'C# 12'. + Projenin dil sürümü en az 'C# 11' olmalıdır. - Language version is required to be at least C# 11 - Dil sürümünün en az C# 11 olması gerekir + Language version is required to be at least C# 12 + Dil sürümünün en az C# 11 olması gerekir diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf index 9d0c0eb3a5d6dd..3dfb711b39b4eb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - 项目的语言版本必须至少为 "C# 11"。 + The project's language version has to be at least 'C# 12'. + 项目的语言版本必须至少为 "C# 11"。 - Language version is required to be at least C# 11 - 语言版本必须至少为 C# 11 + Language version is required to be at least C# 12 + 语言版本必须至少为 C# 11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf index dc6ded618c8e94..9917b18949880e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -28,13 +28,13 @@ - The project's language version has to be at least 'C# 11'. - 專案的語言版本必須至少為 'C# 11'。 + The project's language version has to be at least 'C# 12'. + 專案的語言版本必須至少為 'C# 11'。 - Language version is required to be at least C# 11 - 語言版本要求至少為 C#11 + Language version is required to be at least C# 12 + 語言版本要求至少為 C#11 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 56dddc6f8bc83b..eea01092667e8d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -8,7 +8,6 @@ using System.Globalization; using System.Linq; using System.Reflection; -using System.Text; #if BUILDING_SOURCE_GENERATOR_TESTS using Microsoft.Extensions.Configuration; #endif @@ -2037,6 +2036,7 @@ public void ComplexObj_As_Enumerable_Element() ValidateGeolocation(obj); } +#if !BUILDING_SOURCE_GENERATOR_TESTS [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] public void TraceSwitchTest() { @@ -2056,6 +2056,7 @@ public void TraceSwitchTest() Assert.Equal("Info", ts.Value); #endif // NETCOREAPP } +#endif private void ValidateGeolocation(IGeolocation location) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index 2149dcaaa07141..528847cfeb3a37 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -18,11 +25,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.Collections.Generic; using System.Globalization; using System.Linq; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 12, 17)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -46,16 +60,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -67,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -83,11 +87,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -99,11 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref ICollection obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -115,11 +109,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IReadOnlyList obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - if (obj is not ICollection temp) { return; @@ -136,11 +125,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -152,11 +136,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -168,11 +147,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - if (obj is not IDictionary temp) { return; @@ -189,11 +163,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1) @@ -229,6 +198,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -281,7 +251,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -298,5 +268,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index 406e8db6716777..36ac12fd31f83d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -2,18 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); - - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions)); + using System; + using System.CodeDom.Compiler; - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null); + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -23,20 +24,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -48,11 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -64,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -81,11 +124,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -120,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -163,7 +202,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -180,5 +219,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index 106e01795369e2..02fb06957bb3d5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index a1cb7d6b93b5d0..4703980996b889 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -157,7 +166,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -174,5 +183,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index f3ee8a9ff43840..99371296997168 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index fb71c70b4dd3bd..3e6ce1459b289a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -2,21 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); - - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T)); - - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null); + using System; + using System.CodeDom.Compiler; - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions); + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -26,11 +24,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 12, 38)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 14, 36)] + public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 13, 36)] + public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 15, 36)] + public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); @@ -54,24 +71,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration BindCore(configuration, ref obj, binderOptions); return obj; } - - if (type == typeof(Program.MyClass2)) + else if (type == typeof(Program.MyClass2)) { var obj = new Program.MyClass2(); BindCore(configuration, ref obj, binderOptions); return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -83,11 +94,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - var temp2 = new List(); BindCore(configuration, ref temp2, binderOptions); int originalCount = obj.Length; @@ -97,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -113,11 +114,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -154,11 +150,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value15) @@ -167,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -219,7 +211,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -236,5 +228,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt index c9d49faa937244..e4bcaf6a9b7c95 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt @@ -2,21 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T)); - - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue); - - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key); + using System; + using System.CodeDom.Compiler; - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue; + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -25,11 +23,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); + + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 16, 24)] + public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); + + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 17, 24)] + public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -48,18 +65,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return ParseInt(value, () => section.Path); } - - if (type == typeof(bool?)) + else if (type == typeof(bool?)) { return ParseBool(value, () => section.Path); } - - if (type == typeof(byte[])) + else if (type == typeof(byte[])) { return ParseByteArray(value, () => section.Path); } - - if (type == typeof(CultureInfo)) + else if (type == typeof(CultureInfo)) { return ParseCultureInfo(value, () => section.Path); } @@ -114,5 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt index 17c963bd980a70..2438cf530ca4ce 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt index 1148109b9f5a81..e6db24d522f3c9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt index c833b20f18dcfe..a36f9fafebcff8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt index f773f79ce6c2c0..356f6bb1a933e2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue; + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index de8201fe6fed2c..85d0901de3ff60 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -66,11 +75,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); int originalCount = obj.Length; @@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -96,11 +95,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index 34fadacace146d..d394cc7b269f74 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -66,11 +75,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); int originalCount = obj.Length; @@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -96,11 +95,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt index 16a98c931a705f..83cd88561310ab 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 8d1ee9ed3cd9a3..91714c80cd0136 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index a74dbfdd04b5b9..88b35037c22c3f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -2,31 +2,18 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedOptionsBuilderBinder +namespace System.Runtime.CompilerServices { - /// Registers the dependency injection container to bind against the obtained from the DI service provider. - public static global::Microsoft.Extensions.Options.OptionsBuilder BindConfiguration(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, string configSectionPath, global::System.Action? configureOptions = null) where TOptions : class - { - if (optionsBuilder is null) - { - throw new global::System.ArgumentNullException(nameof(optionsBuilder)); - } + using System; + using System.CodeDom.Compiler; - if (configSectionPath is null) + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configSectionPath)); } - - optionsBuilder.Configure((obj, configuration) => - { - global::Microsoft.Extensions.Configuration.IConfiguration section = string.Equals(string.Empty, configSectionPath, global::System.StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); - global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(section, obj, typeof(TOptions), configureOptions); - }); - - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource>(optionsBuilder.Services); - return optionsBuilder; } } @@ -34,31 +21,74 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region OptionsBuilder extensions. + /// Registers the dependency injection container to bind against the obtained from the DI service provider. + [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] + public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureOptions = null) where TOptions : class + { + if (optionsBuilder is null) + { + throw new ArgumentNullException(nameof(optionsBuilder)); + } + + if (configSectionPath is null) + { + throw new ArgumentNullException(nameof(configSectionPath)); + } + + optionsBuilder.Configure((obj, configuration) => + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); + BindCoreMain(section, obj, typeof(TOptions), configureOptions); + }); + + optionsBuilder.Services.AddSingleton, ConfigurationChangeTokenSource>(); + return optionsBuilder; + } + #endregion OptionsBuilder extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -66,16 +96,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -87,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -110,6 +130,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -162,7 +183,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -179,5 +200,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index ac53b58f24da23..633196e7a742d5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -2,49 +2,18 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedOptionsBuilderBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which will bind against. - public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class - { - return global::GeneratedOptionsBuilderBinder.Bind(optionsBuilder, configuration, configureOptions: null); - } - - /// Registers a configuration instance which will bind against. - public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - if (optionsBuilder is null) - { - throw new global::System.ArgumentNullException(nameof(optionsBuilder)); - } - - global::GeneratedServiceCollectionBinder.Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); - return optionsBuilder; - } -} + using System; + using System.CodeDom.Compiler; -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder -{ - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } @@ -52,31 +21,79 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region OptionsBuilder extensions. + /// Registers a configuration instance which will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration) where TOptions : class + { + return Bind(optionsBuilder, configuration, configureOptions: null); + } + + /// Registers a configuration instance which will bind against. + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (optionsBuilder is null) + { + throw new ArgumentNullException(nameof(optionsBuilder)); + } + + Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + return optionsBuilder; + } + #endregion OptionsBuilder extensions. + + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -84,16 +101,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -105,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -128,6 +135,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -180,7 +188,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -197,5 +205,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index fd3ec70a8a328b..fb5b4b4ad721d8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -2,43 +2,18 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedOptionsBuilderBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which will bind against. - public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - if (optionsBuilder is null) - { - throw new global::System.ArgumentNullException(nameof(optionsBuilder)); - } - - global::GeneratedServiceCollectionBinder.Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); - return optionsBuilder; - } -} + using System; + using System.CodeDom.Compiler; -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder -{ - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } @@ -46,31 +21,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region OptionsBuilder extensions. + /// Registers a configuration instance which will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (optionsBuilder is null) + { + throw new ArgumentNullException(nameof(optionsBuilder)); + } + + Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + return optionsBuilder; + } + #endregion OptionsBuilder extensions. + + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -78,16 +95,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -99,11 +111,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -122,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -174,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -191,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 5d30288a21e785..1bf110454ec7ba 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); - - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); if (configuration["Prop0"] is string value0) @@ -168,6 +191,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -517,5 +541,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 461f6050e2fdfe..7f626f0e27c527 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -2,64 +2,84 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class - { - return global::GeneratedServiceCollectionBinder.Configure(services, string.Empty, configuration, configureOptions: null); - } + using System; + using System.CodeDom.Compiler; - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration) where TOptions : class + { + return Configure(services, string.Empty, configuration, configureOptions: null); + } + + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index a57f652720bc8c..5848c2412f9b78 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -2,64 +2,84 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - return global::GeneratedServiceCollectionBinder.Configure(services, string.Empty, configuration, configureOptions); - } + using System; + using System.CodeDom.Compiler; - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + return Configure(services, string.Empty, configuration, configureOptions); + } + + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index 66975c3164d745..91226d730166f1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -2,64 +2,84 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class - { - return global::GeneratedServiceCollectionBinder.Configure(services, name, configuration, configureOptions: null); - } + using System; + using System.CodeDom.Compiler; - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class + { + return Configure(services, name, configuration, configureOptions: null); + } + + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 0263ef12179401..8c9ccaa71a779f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -2,58 +2,78 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } + using System; + using System.CodeDom.Compiler; - if (configuration is null) + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -61,16 +81,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -82,11 +97,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -97,11 +107,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -112,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -128,11 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -167,6 +162,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -219,7 +215,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -236,5 +232,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs index 8807dfb0962206..c9eb9c70927f99 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs @@ -8,6 +8,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests { public partial class ConfigurationBindingGeneratorTests { + #region IServiceCollection extensions. private string GetConfigureSource(string paramList) => $$""" using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -40,7 +41,9 @@ public class MyClass2 } } """; + #endregion IServiceCollection extensions. + #region OptionsBuilder extensions. [Fact] public async Task Configure_T() => await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); @@ -126,5 +129,6 @@ public class MyClass await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder); await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder); } + #endregion OptionsBuilder extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs index aba2a9f6184f2c..b5c3fb49c5e7eb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -44,7 +43,6 @@ public class MyClass2 { } [Theory] [InlineData(LanguageVersion.Preview)] - [InlineData(LanguageVersion.CSharp11)] public async Task Bind(LanguageVersion langVersion) => await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); @@ -651,7 +649,7 @@ public interface ICustomSet : ISet await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => { - Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count() , d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count())); + Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count())); Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); }); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs index 5bc5145739daac..a512c5efe495b1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs @@ -52,15 +52,17 @@ private enum ExtensionClassType ServiceCollection, } - [Fact] - public async Task LangVersionMustBeCharp11OrHigher() + [Theory] + [InlineData(LanguageVersion.CSharp11)] + [InlineData(LanguageVersion.CSharp10)] + public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion) { - var (d, r) = await RunGenerator(BindCallSampleCode, LanguageVersion.CSharp10); + var (d, r) = await RunGenerator(BindCallSampleCode, langVersion); Assert.Empty(r); Diagnostic diagnostic = Assert.Single(d); Assert.True(diagnostic.Id == "SYSLIB1102"); - Assert.Contains("C# 11", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); + Assert.Contains("C# 12", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity); } @@ -250,9 +252,9 @@ public class MyClass2 { } Assert.Single(r); string generatedSource = string.Join('\n', r[0].SourceText.Lines.Select(x => x.ToString())); - Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass0 obj) => {{ }};", generatedSource); - Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass1 obj, global::System.Action? configureOptions) => {{ }};", generatedSource); - Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass2 obj) => {{ }};", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? obj)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? obj, Action? configureOptions)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? obj)", generatedSource); Assert.Empty(d); } @@ -395,7 +397,7 @@ private static async Task VerifyAgainstBaselineUsingFile( private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( string testSourceCode, - LanguageVersion langVersion = LanguageVersion.CSharp11, + LanguageVersion langVersion = LanguageVersion.Preview, IEnumerable? references = null) => await RoslynTestUtils.RunGenerator( new ConfigurationBindingGenerator(), diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 2108bc2574ed2c..cfd45c365d42a0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -4,7 +4,7 @@ true SYSLIB1100,SYSLIB1101 - + $(Features);InterceptorsPreview true diff --git a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj index 545e2867e4de6c..c0074144e78d9f 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj @@ -3,6 +3,7 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true + $(Features);InterceptorsPreview true true Configuration support for Microsoft.Extensions.Logging. diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index abc5c9d9792eef..0dceab438f82f3 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -7,7 +7,9 @@ $(DefineConstants);NO_SUPPRESS_GC_TRANSITION true true + $(Features);InterceptorsPreview true + true Console logger provider implementation for Microsoft.Extensions.Logging. diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj index f1843ebff94a2a..0676fddc289826 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj @@ -2,9 +2,9 @@ enable $(NetCoreAppCurrent);$(NetFrameworkMinimum) - true $(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER - + $(Features);InterceptorsPreview + true true From b7a3590e9906a9e889cb645b82d526eccc8b02dc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 07:43:57 -0700 Subject: [PATCH 047/345] [release/8.0] Events for IL methods without IL headers (#90844) * Events for IL methods without IL headers Dynamically generated methods like UnsafeAccessor functions are marked as IL, but don't contain an IL header. The lack of header is an indication the IL must be generated at runtime. * Debugger check for no IL header * Update src/coreclr/debug/daccess/stack.cpp Co-authored-by: Tlakaelel Axayakatl Ceja * Review feedback * Remove redundent calls and another spot to check. * Move header include --------- Co-authored-by: Aaron R Robinson Co-authored-by: Tlakaelel Axayakatl Ceja --- src/coreclr/debug/daccess/stack.cpp | 9 +- src/coreclr/inc/eventtracebase.h | 6 +- src/coreclr/utilcode/stresslog.cpp | 2 +- src/coreclr/vm/eventtrace.cpp | 21 ++-- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/method.hpp | 2 +- src/coreclr/vm/prestub.cpp | 116 ++++++++++---------- src/coreclr/vm/versionresilienthashcode.cpp | 8 +- 8 files changed, 90 insertions(+), 76 deletions(-) diff --git a/src/coreclr/debug/daccess/stack.cpp b/src/coreclr/debug/daccess/stack.cpp index 9402d529eb8ea3..6b9f1a491c291c 100644 --- a/src/coreclr/debug/daccess/stack.cpp +++ b/src/coreclr/debug/daccess/stack.cpp @@ -1253,14 +1253,19 @@ ClrDataFrame::GetLocalSig(MetaSig** sig, { // It turns out we cannot really get rid of this check. Dynamic methods // (including IL stubs) do not have their local sig's available after JIT time. - if (!m_methodDesc->IsIL()) + // IL methods with dynamically generated IL (for example, UnsafeAccessors) may + // not have an IL header. + COR_ILMETHOD* ilHeader = m_methodDesc->IsIL() + ? m_methodDesc->GetILHeader() + : NULL; + if (ilHeader == NULL) { *sig = NULL; *count = 0; return E_FAIL; } - COR_ILMETHOD_DECODER methodDecoder(m_methodDesc->GetILHeader()); + COR_ILMETHOD_DECODER methodDecoder(ilHeader); mdSignature localSig = methodDecoder.GetLocalVarSigTok() ? methodDecoder.GetLocalVarSigTok() : mdSignatureNil; if (localSig == mdSignatureNil) diff --git a/src/coreclr/inc/eventtracebase.h b/src/coreclr/inc/eventtracebase.h index 97c3135153038c..3648b1f3a72136 100644 --- a/src/coreclr/inc/eventtracebase.h +++ b/src/coreclr/inc/eventtracebase.h @@ -905,7 +905,7 @@ namespace ETW BOOL fSendRichDebugInfoEvent, BOOL fGetCodeIds); static VOID SendEventsForNgenMethods(Module *pModule, DWORD dwEventOptions); - static VOID SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL); + static VOID SendMethodJitStartEvent(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL); static VOID SendMethodILToNativeMapEvent(MethodDesc * pMethodDesc, DWORD dwEventOptions, PCODE pNativeCodeStartAddress, DWORD nativeCodeId, ReJITID ilCodeId); static VOID SendMethodRichDebugInfo(MethodDesc * pMethodDesc, PCODE pNativeCodeStartAddress, DWORD nativeCodeId, ReJITID ilCodeId, MethodDescSet* sentMethodDetailsSet); static VOID SendMethodEvent(MethodDesc *pMethodDesc, DWORD dwEventOptions, BOOL bIsJit, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL, PCODE pNativeCodeStartAddress = 0, PrepareCodeConfig *pConfig = NULL, MethodDescSet* sentMethodDetailsSet = NULL); @@ -938,7 +938,7 @@ namespace ETW static VOID GetR2RGetEntryPointStart(MethodDesc *pMethodDesc); static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint); - static VOID MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); + static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID SendMethodDetailsEvent(MethodDesc *pMethodDesc); static VOID SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, MethodDescSet* set); @@ -952,7 +952,7 @@ namespace ETW public: static VOID GetR2RGetEntryPointStart(MethodDesc *pMethodDesc) {}; static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint) {}; - static VOID MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); + static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName) {}; static VOID StubsInitialized(PVOID *pHelperStartAddress, PVOID *pHelperNames, LONG ulNoOfHelpers) {}; diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp index c55c5afe9249c8..90ad5900473ed7 100644 --- a/src/coreclr/utilcode/stresslog.cpp +++ b/src/coreclr/utilcode/stresslog.cpp @@ -12,9 +12,9 @@ #include "switches.h" #include "stresslog.h" #include "clrhost.h" +#include "ex.h" #define DONOT_DEFINE_ETW_CALLBACK #include "eventtracebase.h" -#include "ex.h" #if !defined(STRESS_LOG_READONLY) #ifdef HOST_WINDOWS diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index b9a82cfb7c28e9..9498f00edf4329 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -3555,7 +3555,7 @@ VOID ETW::MethodLog::MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrC /*************************************************/ /* This is called by the runtime when method jitting started */ /*************************************************/ -VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) +VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) { CONTRACTL { NOTHROW; @@ -3570,7 +3570,7 @@ VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOr CLR_JIT_KEYWORD)) { pMethodDesc->GetMethodInfo(*namespaceOrClassName, *methodName, *methodSignature); - ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, namespaceOrClassName, methodName, methodSignature); + ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, methodDecoder, namespaceOrClassName, methodName, methodSignature); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -4528,7 +4528,12 @@ VOID ETW::MethodLog::SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, /*****************************************************************/ /* This routine is used to send an ETW event just before a method starts jitting*/ /*****************************************************************/ -VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) +VOID ETW::MethodLog::SendMethodJitStartEvent( + MethodDesc *pMethodDesc, + COR_ILMETHOD_DECODER* methodDecoder, + SString *namespaceOrClassName, + SString *methodName, + SString *methodSignature) { CONTRACTL { THROWS; @@ -4566,15 +4571,13 @@ VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *n ulMethodToken = (ULONG)0; } else - ulMethodToken = (ULONG)pMethodDesc->GetMemberDef(); - - if(pMethodDesc->IsIL()) { - COR_ILMETHOD_DECODER::DecoderStatus decoderstatus = COR_ILMETHOD_DECODER::FORMAT_ERROR; - COR_ILMETHOD_DECODER ILHeader(pMethodDesc->GetILHeader(), pMethodDesc->GetMDImport(), &decoderstatus); - ulMethodILSize = (ULONG)ILHeader.GetCodeSize(); + ulMethodToken = (ULONG)pMethodDesc->GetMemberDef(); } + if (methodDecoder != NULL) + ulMethodILSize = methodDecoder->GetCodeSize(); + SString tNamespace, tMethodName, tMethodSignature; if(!namespaceOrClassName|| !methodName|| !methodSignature || (methodName->IsEmpty() && namespaceOrClassName->IsEmpty() && methodSignature->IsEmpty())) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 1a3439bdd235ef..74ee2f7482e747 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -12286,7 +12286,7 @@ static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr, SString namespaceOrClassName, methodName, methodSignature; // Fire an ETW event to mark the beginning of JIT'ing - ETW::MethodLog::MethodJitting(reinterpret_cast(info->ftn), &namespaceOrClassName, &methodName, &methodSignature); + ETW::MethodLog::MethodJitting(reinterpret_cast(info->ftn), NULL, &namespaceOrClassName, &methodName, &methodSignature); CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 4b34045b57671e..e51d9f7453d35e 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1819,7 +1819,7 @@ class MethodDesc PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0); PCODE JitCompileCode(PrepareCodeConfig* pConfig); PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry); - PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode); + PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode); public: bool TryGenerateUnsafeAccessor(DynamicResolver** resolver, COR_ILMETHOD_DECODER** methodILDecoder); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 174e48565f31b8..32944952301648 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -709,6 +709,53 @@ PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig) } } +namespace +{ + COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pDecoderMemory) + { + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL); + _ASSERTE(!pMD->IsNoMetadata()); + _ASSERTE(pConfig != NULL); + _ASSERTE(pDecoderMemory != NULL); + + COR_ILMETHOD_DECODER* pHeader = NULL; + COR_ILMETHOD* ilHeader = pConfig->GetILHeader(); + if (ilHeader == NULL) + return NULL; + + COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::FORMAT_ERROR; + { + // Decoder ctor can AV on a malformed method header + AVInRuntimeImplOkayHolder AVOkay; + pHeader = new (pDecoderMemory) COR_ILMETHOD_DECODER(ilHeader, pMD->GetMDImport(), &status); + } + + if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) + COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); + + return pHeader; + } + + COR_ILMETHOD_DECODER* GetAndVerifyILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory) + { + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL); + if (pMD->IsIL()) + { + return GetAndVerifyMetadataILHeader(pMD, pConfig, pIlDecoderMemory); + } + else if (pMD->IsILStub()) + { + ILStubResolver* pResolver = pMD->AsDynamicMethodDesc()->GetILStubResolver(); + return pResolver->GetILHeader(); + } + + _ASSERTE(pMD->IsNoMetadata()); + return NULL; + } +} + PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry) { STANDARD_VM_CONTRACT; @@ -759,11 +806,18 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J } #endif // PROFILING_SUPPORTED + // The profiler may have changed the code on the callback. Need to + // pick up the new code. + // + // (don't want this for OSR, need to see how it works) + COR_ILMETHOD_DECODER ilDecoderTemp; + COR_ILMETHOD_DECODER* pilHeader = GetAndVerifyILHeader(this, pConfig, &ilDecoderTemp); + if (!ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_JIT_KEYWORD)) { - pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode); + pCode = JitCompileCodeLocked(pConfig, pilHeader, pEntry, &sizeOfCode); } else { @@ -778,12 +832,13 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J // a small stub of native code but no native-IL mapping. #ifndef FEATURE_INTERPRETER ETW::MethodLog::MethodJitting(this, + pilHeader, &namespaceOrClassName, &methodName, &methodSignature); #endif - pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode); + pCode = JitCompileCodeLocked(pConfig, pilHeader, pEntry, &sizeOfCode); // Interpretted methods skip this notification #ifdef FEATURE_INTERPRETER @@ -869,66 +924,11 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J return pCode; } -namespace -{ - COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pDecoderMemory) - { - STANDARD_VM_CONTRACT; - _ASSERTE(pMD != NULL); - _ASSERTE(!pMD->IsNoMetadata()); - _ASSERTE(pConfig != NULL); - _ASSERTE(pDecoderMemory != NULL); - - COR_ILMETHOD_DECODER* pHeader = NULL; - COR_ILMETHOD* ilHeader = pConfig->GetILHeader(); - if (ilHeader == NULL) - return NULL; - - COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::FORMAT_ERROR; - { - // Decoder ctor can AV on a malformed method header - AVInRuntimeImplOkayHolder AVOkay; - pHeader = new (pDecoderMemory) COR_ILMETHOD_DECODER(ilHeader, pMD->GetMDImport(), &status); - } - - if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); - - return pHeader; - } - - COR_ILMETHOD_DECODER* GetAndVerifyILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory) - { - STANDARD_VM_CONTRACT; - _ASSERTE(pMD != NULL); - if (pMD->IsIL()) - { - return GetAndVerifyMetadataILHeader(pMD, pConfig, pIlDecoderMemory); - } - else if (pMD->IsILStub()) - { - ILStubResolver* pResolver = pMD->AsDynamicMethodDesc()->GetILStubResolver(); - return pResolver->GetILHeader(); - } - - _ASSERTE(pMD->IsNoMetadata()); - return NULL; - } -} - -PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, ULONG* pSizeOfCode) +PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pEntry, ULONG* pSizeOfCode) { STANDARD_VM_CONTRACT; PCODE pCode = NULL; - - // The profiler may have changed the code on the callback. Need to - // pick up the new code. - // - // (don't want this for OSR, need to see how it works) - COR_ILMETHOD_DECODER ilDecoderTemp; - COR_ILMETHOD_DECODER* pilHeader = GetAndVerifyILHeader(this, pConfig, &ilDecoderTemp); - CORJIT_FLAGS jitFlags; PCODE pOtherCode = NULL; diff --git a/src/coreclr/vm/versionresilienthashcode.cpp b/src/coreclr/vm/versionresilienthashcode.cpp index b3ba764baac595..85bd146d8dc463 100644 --- a/src/coreclr/vm/versionresilienthashcode.cpp +++ b/src/coreclr/vm/versionresilienthashcode.cpp @@ -286,7 +286,7 @@ bool AddVersionResilientHashCodeForInstruction(ILInstructionParser *parser, xxHa hash->Add(varValue); break; } - + case InlineVar: // 2 byte value which is token change resilient { uint16_t varValue; @@ -388,6 +388,12 @@ bool GetVersionResilientILCodeHashCode(MethodDesc *pMD, int* hashCode, unsigned* initLocals = (options & CORINFO_OPT_INIT_LOCALS) == CORINFO_OPT_INIT_LOCALS; } + else if (!pMD->HasILHeader()) + { + // Dynamically generated IL methods like UnsafeAccessors may not have + // an IL header. + return false; + } else { COR_ILMETHOD_DECODER header(pMD->GetILHeader(TRUE), pMD->GetMDImport(), NULL); From b7905da1ae57c6ebf5999d9cea319da049e5b512 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 09:49:58 -0700 Subject: [PATCH 048/345] [release/8.0] Change OneLocBuild mirror branch to release/8.0 (#90813) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [main] Change OneLocBuild mirror branch to release/8.0 temporarily * Re-enable OneLocBuild in runtime-official.yml * Do not modify common, add the parameter in the uncommented lines instead. * Revert spacing * Change condition --------- Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- eng/pipelines/runtime-official.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 172a40e24d169f..46f7872817e8f3 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -41,13 +41,13 @@ extends: # Localization build # - # disabled due to https://github.com/dotnet/runtime/issues/90466 - #- ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/main') }}: - # - template: /eng/common/templates/job/onelocbuild.yml - # parameters: - # MirrorRepo: runtime - # LclSource: lclFilesfromPackage - # LclPackageId: 'LCL-JUNO-PROD-RUNTIME' + - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/8.0') }}: + - template: /eng/common/templates/job/onelocbuild.yml + parameters: + MirrorRepo: runtime + MirrorBranch: release/8.0 + LclSource: lclFilesfromPackage + LclPackageId: 'LCL-JUNO-PROD-RUNTIME' # # Source Index Build From a54450d065ebd780b936213100546568d16e814f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:52:27 -0700 Subject: [PATCH 049/345] Add missing space in yaml (#90894) Co-authored-by: Matt Mitchell --- eng/pipelines/runtime-official.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 46f7872817e8f3..9c341a04791289 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -42,12 +42,12 @@ extends: # - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/8.0') }}: - - template: /eng/common/templates/job/onelocbuild.yml - parameters: - MirrorRepo: runtime - MirrorBranch: release/8.0 - LclSource: lclFilesfromPackage - LclPackageId: 'LCL-JUNO-PROD-RUNTIME' + - template: /eng/common/templates/job/onelocbuild.yml + parameters: + MirrorRepo: runtime + MirrorBranch: release/8.0 + LclSource: lclFilesfromPackage + LclPackageId: 'LCL-JUNO-PROD-RUNTIME' # # Source Index Build From 9c4d1a368bb002cd02e7ee62c06cfcb0ff54f2b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 09:19:48 -0700 Subject: [PATCH 050/345] Fix queue count in rate limiters (#90878) Co-authored-by: Brennan --- .../RateLimiting/ConcurrencyLimiter.cs | 40 ++++++++++++++++--- .../RateLimiting/FixedWindowRateLimiter.cs | 39 +++++++++++++++--- .../RateLimiting/SlidingWindowRateLimiter.cs | 39 +++++++++++++++--- .../RateLimiting/TokenBucketRateLimiter.cs | 40 ++++++++++++++++--- 4 files changed, 136 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs index 6b5a4014990ef0..7131b4fe1d7999 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/ConcurrencyLimiter.cs @@ -156,8 +156,17 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - // Updating queue count is handled by the cancellation code - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -277,10 +286,19 @@ private void Release(int releaseCount) // Check if request was canceled if (!nextPendingRequest.TrySetResult(lease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _permitCount += nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -399,6 +417,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -429,7 +450,14 @@ private static void Cancel(object? state) var limiter = (ConcurrencyLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs index d09c7973b18aa7..daaed9cf5ce422 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/FixedWindowRateLimiter.cs @@ -173,7 +173,17 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -330,10 +340,19 @@ private void ReplenishInternal(long nowTicks) if (!nextPendingRequest.TrySetResult(SuccessfulLease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _permitCount += nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -435,6 +454,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -465,7 +487,14 @@ private static void Cancel(object? state) var limiter = (FixedWindowRateLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs index a179720ede33fa..23dbf98e0fcdea 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/SlidingWindowRateLimiter.cs @@ -185,7 +185,17 @@ protected override ValueTask AcquireAsyncCore(int permitCount, C Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -342,11 +352,20 @@ private void ReplenishInternal(long nowTicks) if (!nextPendingRequest.TrySetResult(SuccessfulLease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _permitCount += nextPendingRequest.Count; _requestsPerSegment[_currentSegmentIndex] -= nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -448,6 +467,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -478,7 +500,14 @@ private static void Cancel(object? state) var limiter = (SlidingWindowRateLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } diff --git a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs index 5ad7859792ff7f..67a3a55a29ad03 100644 --- a/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs +++ b/src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/TokenBucketRateLimiter.cs @@ -178,8 +178,17 @@ protected override ValueTask AcquireAsyncCore(int tokenCount, Ca Debug.Assert(_queueCount >= 0); if (!oldestRequest.TrySetResult(FailedLease)) { - // Updating queue count is handled by the cancellation code - _queueCount += oldestRequest.Count; + if (!oldestRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + oldestRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += oldestRequest.Count; + } } else { @@ -345,10 +354,19 @@ private void ReplenishInternal(long nowTicks) if (!nextPendingRequest.TrySetResult(SuccessfulLease)) { - // Queued item was canceled so add count back + // Queued item was canceled so add count back, permits weren't acquired _tokenCount += nextPendingRequest.Count; - // Updating queue count is handled by the cancellation code - _queueCount += nextPendingRequest.Count; + if (!nextPendingRequest.QueueCountModified) + { + // We already updated the queue count, the Cancel code is about to run or running and waiting on our lock, + // tell Cancel not to do anything + nextPendingRequest.QueueCountModified = true; + } + else + { + // Updating queue count was handled by the cancellation code, don't double count + _queueCount += nextPendingRequest.Count; + } } else { @@ -450,6 +468,9 @@ private sealed class RequestRegistration : TaskCompletionSource private readonly CancellationToken _cancellationToken; private CancellationTokenRegistration _cancellationTokenRegistration; + // Update under the limiter lock and only if the queue count was updated by the calling code + public bool QueueCountModified { get; set; } + // this field is used only by the disposal mechanics and never shared between threads private RequestRegistration? _next; @@ -480,7 +501,14 @@ private static void Cancel(object? state) var limiter = (TokenBucketRateLimiter)registration.Task.AsyncState!; lock (limiter.Lock) { - limiter._queueCount -= registration.Count; + // Queuing and replenishing code might modify the _queueCount, since there is no guarantee of when the cancellation + // code runs and we only want to update the _queueCount once, we set a bool (under a lock) so either method + // can update the count and not double count. + if (!registration.QueueCountModified) + { + limiter._queueCount -= registration.Count; + registration.QueueCountModified = true; + } } } } From 38e682f69e71b0ee46f92ef0ddc57a060d197812 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:38:21 -0600 Subject: [PATCH 051/345] [release/8.0] Update Fedora docker image to Fedora 38 (#90930) * Update Fedora image to Fedora 38 * (to revert) commit to check Fedora image specifically * Revert "(to revert) commit to check Fedora image specifically" This reverts commit 2e2d14e8d9586e5400ce3d7f7afd6ae26e9d9a6c. --------- Co-authored-by: Natalia Kondratyeva --- eng/pipelines/libraries/helix-queues-setup.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 72d8d53cd94ddd..987d7f99c41f4a 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -62,13 +62,13 @@ jobs: - ${{ if and(eq(parameters.jobParameters.testScope, 'outerloop'), eq(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - SLES.15.Amd64.Open - (Centos.8.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8-helix - - (Fedora.36.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-36-helix + - (Fedora.38.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-38-helix - (Ubuntu.2204.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-helix-amd64 - (Debian.11.Amd64.Open)Ubuntu.2204.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64 - ${{ if or(ne(parameters.jobParameters.testScope, 'outerloop'), ne(parameters.jobParameters.runtimeFlavor, 'mono')) }}: - ${{ if or(eq(parameters.jobParameters.isExtraPlatforms, true), eq(parameters.jobParameters.includeAllPlatforms, true)) }}: - SLES.15.Amd64.Open - - (Fedora.36.Amd64.Open)ubuntu.1804.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-36-helix + - (Fedora.38.Amd64.Open)ubuntu.1804.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-38-helix - Ubuntu.2204.Amd64.Open - (Debian.11.Amd64.Open)Ubuntu.1804.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-helix-amd64 - (Mariner.2.0.Amd64.Open)ubuntu.1804.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-helix-amd64 From d727d86b2c6270bfd7a75c0c53ce87ec6fc6fda5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:40:21 -0600 Subject: [PATCH 052/345] Update Microsoft.Extensions.Http.cs (#90920) Update ref, add missing `this` to extension method parameter Co-authored-by: Shreyas Jejurkar --- .../Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs index 9071751734f946..51891e8ebcf754 100644 --- a/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs +++ b/src/libraries/Microsoft.Extensions.Http/ref/Microsoft.Extensions.Http.cs @@ -57,7 +57,7 @@ public static partial class HttpClientFactoryServiceCollectionExtensions public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureClient) where TClient : class where TImplementation : class, TClient { throw null; } public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Func factory) where TClient : class where TImplementation : class, TClient { throw null; } public static Microsoft.Extensions.DependencyInjection.IHttpClientBuilder AddHttpClient(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Func factory) where TClient : class where TImplementation : class, TClient { throw null; } - public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureHttpClientDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureHttpClientDefaults(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) { throw null; } } public partial interface IHttpClientBuilder { From 12d9907a0d8ca865767b08e99ab359a18f923cc6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 13:59:33 -0600 Subject: [PATCH 053/345] [release/8.0] Update dependencies from 7 repositories (#90766) * Update dependencies from https://github.com/dotnet/icu build 20230814.4 Microsoft.NETCore.Runtime.ICU.Transport From Version 8.0.0-rc.1.23407.2 -> To Version 9.0.0-alpha.1.23414.4 * Update dependencies from https://github.com/dotnet/msquic build 20230812.1 System.Net.MsQuic.Transport From Version 8.0.0-alpha.1.23166.1 -> To Version 8.0.0-alpha.1.23412.1 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230816.1 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23412.1 -> To Version 3.11.0-beta1.23416.1 * Update dependencies from https://github.com/dotnet/cecil build 20230814.1 Microsoft.DotNet.Cecil From Version 0.11.4-alpha.23407.2 -> To Version 0.11.4-alpha.23414.1 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230817.2 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23412.1 -> To Version 3.11.0-beta1.23417.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230814.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23381.3 -> To Version 8.0.0-alpha.1.23414.1 * Revert "Update dependencies from https://github.com/dotnet/icu build 20230814.4" This reverts commit 6e553e10c4977a6040aa044a608bb1181bb391b6. * Update dependencies from https://github.com/dotnet/icu build 20230818.1 Microsoft.NETCore.Runtime.ICU.Transport From Version 8.0.0-rc.1.23407.2 -> To Version 8.0.0-rc.2.23418.1 * Update dependencies from https://github.com/dotnet/arcade build 20230817.3 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23415.4 -> To Version 8.0.0-beta.23417.3 * Dependency coherency updates Microsoft.DotNet.XliffTasks From Version 1.0.0-beta.23415.1 -> To Version 1.0.0-beta.23416.1 (parent: Microsoft.DotNet.Arcade.Sdk * Update dependencies from https://github.com/dotnet/arcade build 20230819.1 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23415.4 -> To Version 8.0.0-beta.23419.1 Dependency coherency updates Microsoft.DotNet.XliffTasks From Version 1.0.0-beta.23415.1 -> To Version 1.0.0-beta.23418.1 (parent: Microsoft.DotNet.Arcade.Sdk * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230820.2 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23412.1 -> To Version 3.11.0-beta1.23420.2 * Update dependencies from https://github.com/dotnet/cecil build 20230821.1 Microsoft.DotNet.Cecil From Version 0.11.4-alpha.23407.2 -> To Version 0.11.4-alpha.23421.1 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20230821.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 8.0.0-alpha.0.23407.2 -> To Version 8.0.0-alpha.0.23421.1 * Update dependencies from https://github.com/dotnet/icu build 20230821.2 Microsoft.NETCore.Runtime.ICU.Transport From Version 8.0.0-rc.1.23407.2 -> To Version 8.0.0-rc.2.23421.2 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230821.3 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23412.1 -> To Version 3.11.0-beta1.23421.3 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230821.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23381.3 -> To Version 8.0.0-alpha.1.23421.1 * [wasm] Fix Wasm.Build.Tests build (#90927) Prompted by the following getting caught as a warning, and converted to an error, on windows: ``` EXEC : error : dotnet-install: Failed to check the disk space. Installation will continue, but it may fail if you do not have [D:\a\_work\1\s\src\mono\wasm\Wasm.Build.Tests\Wasm.Build.Tests.csproj] enough disk space. dotnet-install: Extracting the archive. ``` (cherry picked from commit 09d7b439fa362c23d6546d1bce9a0a244ff2448f) --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing Co-authored-by: Ankit Jain --- eng/Version.Details.xml | 104 +++++++++++------------ eng/Versions.props | 42 ++++----- eng/common/native/init-compiler.sh | 2 +- eng/common/sdl/trim-assets-version.ps1 | 2 +- eng/common/templates/job/execute-sdl.yml | 5 ++ eng/testing/workloads-testing.targets | 1 + global.json | 6 +- 7 files changed, 84 insertions(+), 78 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6d255bdbc9f2af..492aa254177b02 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,12 +1,12 @@ - + https://github.com/dotnet/icu - 92124838d3f0efde3ac483a904691a611babb9a0 + b70521e39f983ec3da46cb4885da3a99e3477724 - + https://github.com/dotnet/msquic - a880e93af4e50d19110d228e698900c110e2b0e9 + 72811ab66f2611ac9f652cbb020dba033fc37401 https://github.com/dotnet/wcf @@ -85,9 +85,9 @@ 02fe27cd6a9b001c8feb7938e6ef4b3799745759b - + https://github.com/dotnet/cecil - 2f4ef297939628143389ddeea569874ded0b1c1b + d412306c1514a26737574838900052d8758da5be @@ -95,9 +95,9 @@ 66dbaefff04250dc72849f0172e0c53bcfb3ab38 - + https://github.com/dotnet/source-build-reference-packages - 5a1492557c8717b428b69fd4b7ca8c91d5d18cd3 + f4903e46459e0348e3793055dd8b68b8b0264034 @@ -107,79 +107,79 @@ - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/xliff-tasks - 649a1e75101b701d753ee41efbe9038f9b23a0db + bb654cd4736e7e8cb99f1c355ce2b8f0a686ba74 - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc https://github.com/dotnet/runtime-assets @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 46ff142f43e887d5f9a4d87ef39d72166f61db8d + 385129cbc980a515ddee2fa56f6b16f3183ed9bc https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -350,9 +350,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 068998a5d91f55a619d1d072ab3094dacd5d6a4f - + https://github.com/dotnet/hotreload-utils - 696312fd2a60671797b12311a4cf387d3cd14dd0 + e02247b9b7ec1d9e407312342147d8587a8ca20e https://github.com/dotnet/runtime-assets @@ -371,13 +371,13 @@ https://github.com/dotnet/roslyn 1fd4ff9d594b227baa3fc0962e2251323311ec19 - + https://github.com/dotnet/roslyn-analyzers - 755a4f888d64fc7c0f2802adca731f301a53283d + 76d99c5f3e11f0600fae074270c0d89042c360f0 - + https://github.com/dotnet/roslyn-analyzers - 755a4f888d64fc7c0f2802adca731f301a53283d + 76d99c5f3e11f0600fae074270c0d89042c360f0 https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index 314fcfd8e52f16..7760bd9a6a9686 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.23412.1 - 8.0.0-preview.23412.1 + 3.11.0-beta1.23421.3 + 8.0.0-preview.23421.3 8.0.100-preview.7.23329.3 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 2.5.1-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 - 8.0.0-beta.23415.4 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 2.5.1-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 + 8.0.0-beta.23419.1 6.0.0-preview.1.102 @@ -184,7 +184,7 @@ 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 - 8.0.0-alpha.0.23407.2 + 8.0.0-alpha.0.23421.1 2.4.2 1.0.0 2.4.5 @@ -213,14 +213,14 @@ 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23407.2 + 0.11.4-alpha.23421.1 8.0.0-rc.1.23406.6 - 8.0.0-rc.1.23407.2 + 8.0.0-rc.2.23421.2 2.2.2 - 8.0.0-alpha.1.23180.2 + 8.0.0-alpha.1.23412.1 16.0.5-alpha.1.23408.1 16.0.5-alpha.1.23408.1 diff --git a/eng/common/native/init-compiler.sh b/eng/common/native/init-compiler.sh index 517401b688bf76..f5c1ec7eafeb28 100644 --- a/eng/common/native/init-compiler.sh +++ b/eng/common/native/init-compiler.sh @@ -63,7 +63,7 @@ if [ -z "$CLR_CC" ]; then # Set default versions if [ -z "$majorVersion" ]; then # note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero. - if [ "$compiler" = "clang" ]; then versions="16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5" + if [ "$compiler" = "clang" ]; then versions="17 16 15 14 13 12 11 10 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5" elif [ "$compiler" = "gcc" ]; then versions="13 12 11 10 9 8 7 6 5 4.9"; fi for version in $versions; do diff --git a/eng/common/sdl/trim-assets-version.ps1 b/eng/common/sdl/trim-assets-version.ps1 index d8cfec910c77e6..a2e0048770452f 100644 --- a/eng/common/sdl/trim-assets-version.ps1 +++ b/eng/common/sdl/trim-assets-version.ps1 @@ -25,7 +25,7 @@ function Install-VersionTools-Cli { Write-Host "Installing the package '$CliToolName' with a version of '$version' ..." $feed = "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" - $argumentList = @("tool", "install", "--local", "$CliToolName", "--add-source $feed", "--no-cache", "--version $Version") + $argumentList = @("tool", "install", "--local", "$CliToolName", "--add-source $feed", "--no-cache", "--version $Version", "--create-manifest-if-needed") Start-Process "$dotnet" -Verbose -ArgumentList $argumentList -NoNewWindow -Wait } diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 7aabaa18017bf6..7870f93bc17652 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -105,6 +105,11 @@ jobs: downloadPath: $(Build.ArtifactStagingDirectory)\artifacts checkDownloadedFiles: true + - powershell: eng/common/sdl/trim-assets-version.ps1 + -InputPath $(Build.ArtifactStagingDirectory)\artifacts + displayName: Trim the version from the NuGet packages + continueOnError: ${{ parameters.sdlContinueOnError }} + - powershell: eng/common/sdl/extract-artifact-packages.ps1 -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts diff --git a/eng/testing/workloads-testing.targets b/eng/testing/workloads-testing.targets index 2961313c84973d..df5526e3f11583 100644 --- a/eng/testing/workloads-testing.targets +++ b/eng/testing/workloads-testing.targets @@ -76,6 +76,7 @@ Command="chmod +x $(_DotNetInstallScriptPath); $(_DotNetInstallCommand)" /> diff --git a/global.json b/global.json index cf4ac698e3e8cb..4142e57fcf5613 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23415.4", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23415.4", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23415.4", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23419.1", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23419.1", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23419.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From 5661a200c9fb5d2d58e2268b9dd11ee88caf853a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:45:25 -0600 Subject: [PATCH 054/345] [release/8.0] Error out when NativeLib has EventPipe enabled (#90934) * Error out when NativeLib has EventPipe enabled * Update src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets Co-authored-by: Andy Gocke * Update src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets Co-authored-by: Jan Kotas --------- Co-authored-by: Lakshan Fernando Co-authored-by: Andy Gocke Co-authored-by: Jan Kotas --- .../BuildIntegration/Microsoft.NETCore.Native.Publish.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets index 647aee4993d960..32eefb307eb0fd 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets @@ -50,6 +50,8 @@ Text="RuntimeIdentifier is required for native compilation. Try running dotnet publish with the -r option value specified." /> + + From d4c6dd6b94f43424a9bea7b9eb905f0df6945a89 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 18:21:57 -0700 Subject: [PATCH 055/345] [release/8.0] [NativeAOT] Missing memory fence before bulk move of objects (#90941) * Memory fence before bulk move of objects * deleted GCMemoryHelpers.h * Introduced a GCHeapMemoryBarrier helper. --------- Co-authored-by: vsadov <8218165+VSadov@users.noreply.github.com> --- .../nativeaot/Runtime/GCMemoryHelpers.cpp | 21 +++++++++++++------ .../nativeaot/Runtime/GCMemoryHelpers.h | 8 ------- src/coreclr/nativeaot/Runtime/MiscHelpers.cpp | 1 - src/coreclr/nativeaot/Runtime/gcrhenv.cpp | 1 - src/coreclr/nativeaot/Runtime/portable.cpp | 1 - src/coreclr/nativeaot/Runtime/threadstore.cpp | 1 - 6 files changed, 15 insertions(+), 18 deletions(-) delete mode 100644 src/coreclr/nativeaot/Runtime/GCMemoryHelpers.h diff --git a/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.cpp b/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.cpp index 27126acbdb839f..30f2c5c5fd3e9a 100644 --- a/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.cpp @@ -10,7 +10,6 @@ #include "PalRedhawkCommon.h" #include "CommonMacros.inl" -#include "GCMemoryHelpers.h" #include "GCMemoryHelpers.inl" // This function clears a piece of memory in a GC safe way. @@ -31,11 +30,26 @@ COOP_PINVOKE_CDECL_HELPER(void *, RhpGcSafeZeroMemory, (void * mem, size_t size) return mem; } +#if defined(TARGET_X86) || defined(TARGET_AMD64) + // + // Memory writes are already ordered + // + #define GCHeapMemoryBarrier() +#else + #define GCHeapMemoryBarrier() MemoryBarrier() +#endif + // Move memory, in a way that is compatible with a move onto the heap, but // does not require the destination pointer to be on the heap. COOP_PINVOKE_HELPER(void, RhBulkMoveWithWriteBarrier, (uint8_t* pDest, uint8_t* pSrc, size_t cbDest)) { + // It is possible that the bulk write is publishing object references accessible so far only + // by the current thread to shared memory. + // The memory model requires that writes performed by current thread are observable no later + // than the writes that will actually publish the references. + GCHeapMemoryBarrier(); + if (pDest <= pSrc || pSrc + cbDest <= pDest) InlineForwardGCSafeCopy(pDest, pSrc, cbDest); else @@ -43,8 +57,3 @@ COOP_PINVOKE_HELPER(void, RhBulkMoveWithWriteBarrier, (uint8_t* pDest, uint8_t* InlinedBulkWriteBarrier(pDest, cbDest); } - -void REDHAWK_CALLCONV RhpBulkWriteBarrier(void* pMemStart, uint32_t cbMemSize) -{ - InlinedBulkWriteBarrier(pMemStart, cbMemSize); -} diff --git a/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.h b/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.h deleted file mode 100644 index 127b4d772040ab..00000000000000 --- a/src/coreclr/nativeaot/Runtime/GCMemoryHelpers.h +++ /dev/null @@ -1,8 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// Unmanaged GC memory helpers -// - -EXTERN_C void REDHAWK_CALLCONV RhpBulkWriteBarrier(void* pMemStart, uint32_t cbMemSize); diff --git a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp index ec2fabcc540f1f..6df37cf23b9d36 100644 --- a/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp +++ b/src/coreclr/nativeaot/Runtime/MiscHelpers.cpp @@ -35,7 +35,6 @@ #include "MethodTable.inl" #include "CommonMacros.inl" #include "volatile.h" -#include "GCMemoryHelpers.h" #include "GCMemoryHelpers.inl" #include "yieldprocessornormalized.h" #include "RhConfig.h" diff --git a/src/coreclr/nativeaot/Runtime/gcrhenv.cpp b/src/coreclr/nativeaot/Runtime/gcrhenv.cpp index 3d0990962b7c99..3ec488605c1b33 100644 --- a/src/coreclr/nativeaot/Runtime/gcrhenv.cpp +++ b/src/coreclr/nativeaot/Runtime/gcrhenv.cpp @@ -42,7 +42,6 @@ #include "daccess.h" -#include "GCMemoryHelpers.h" #include "interoplibinterface.h" #include "holder.h" diff --git a/src/coreclr/nativeaot/Runtime/portable.cpp b/src/coreclr/nativeaot/Runtime/portable.cpp index d45b3d062d00e3..8b425bfe2dff12 100644 --- a/src/coreclr/nativeaot/Runtime/portable.cpp +++ b/src/coreclr/nativeaot/Runtime/portable.cpp @@ -31,7 +31,6 @@ #include "MethodTable.inl" #include "ObjectLayout.h" -#include "GCMemoryHelpers.h" #include "GCMemoryHelpers.inl" #if defined(USE_PORTABLE_HELPERS) diff --git a/src/coreclr/nativeaot/Runtime/threadstore.cpp b/src/coreclr/nativeaot/Runtime/threadstore.cpp index 67a6949fd7fb06..2e8369f9175fc5 100644 --- a/src/coreclr/nativeaot/Runtime/threadstore.cpp +++ b/src/coreclr/nativeaot/Runtime/threadstore.cpp @@ -24,7 +24,6 @@ #include "yieldprocessornormalized.h" #include "slist.inl" -#include "GCMemoryHelpers.h" EXTERN_C volatile uint32_t RhpTrapThreads; volatile uint32_t RhpTrapThreads = (uint32_t)TrapThreadsFlags::None; From 6f0dd7cb1b0624a6d6de38351b665fa317a53fa2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 22:22:54 -0700 Subject: [PATCH 056/345] Update dependencies from https://github.com/dotnet/arcade build 20230817.3 (#90814) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23415.4 -> To Version 8.0.0-beta.23417.3 Dependency coherency updates Microsoft.DotNet.XliffTasks From Version 1.0.0-beta.23415.1 -> To Version 1.0.0-beta.23416.1 (parent: Microsoft.DotNet.Arcade.Sdk Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> From ba6a4adb228567a6bb3f4a9e5789fb74c47c8c94 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 08:59:19 -0700 Subject: [PATCH 057/345] Update dependencies from https://github.com/dotnet/arcade build 20230822.1 (#90983) Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23419.1 -> To Version 8.0.0-beta.23422.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 72 +++++++++---------- eng/Versions.props | 30 ++++---- eng/common/loc/P22DotNetHtmlLocalization.lss | Bin 3842 -> 1876 bytes global.json | 6 +- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 492aa254177b02..270d5c0b3ad3e8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -107,9 +107,9 @@ - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b @@ -117,69 +117,69 @@ bb654cd4736e7e8cb99f1c355ce2b8f0a686ba74 - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b https://github.com/dotnet/runtime-assets @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 385129cbc980a515ddee2fa56f6b16f3183ed9bc + 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 7760bd9a6a9686..f86168bdf919a3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,21 +85,21 @@ 8.0.100-preview.7.23329.3 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 2.5.1-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 - 8.0.0-beta.23419.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 2.5.1-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 + 8.0.0-beta.23422.1 6.0.0-preview.1.102 diff --git a/eng/common/loc/P22DotNetHtmlLocalization.lss b/eng/common/loc/P22DotNetHtmlLocalization.lss index 858a0b237c62ce4f2ee12aa14794f160f6b122b7..5d892d619398f9feeac4cefc1c53ff18a807f732 100644 GIT binary patch literal 1876 zcmd5-O>Y`85WVMDO!tse0|`=3Kq5qFvJwFroLr(PGHdUyD`QjJ8$y14$Ln3lZW2{J zwGs!I&o^(Lhrz|mTEa6oR%kVh&N`>j#re@-x_nwr2#IG`%ct-0baH+K&@f(3mgC!a zLE`z$`_TL4VSG6vqld@GGPwJ;L@RorHxAn^xdXw5(R4X4f7_@k)pTF-lorz22$--N zNp~~4=EJDUfxSBovWjDy#&0y*A$Y%{951Lgf#O!hPmkZU}#I!)Wng z1f<%)R3}u5SL$^NOII+VJC!`W+V>zz0i%$|xtEKJRoWJsS2-4>j6oFy0;9}2)ZXS? z!4+5B;BS?^g*W;n#c6Okuah`~R7l#LlUM`Wwgi;X`GgRCXg2Aj93+p!!wlyufdm#b2J0d!FWGIX~B#Nn{?*T z-%qWy16eI?CAp^@t!rT|vicQ-vsH(!kP=oLa9cnNr~Mvq*K+4!SBpR#0ixlQVLn!4 z_-b`9x-gH#c?z0gti{WerraQ#kQ%)%r?a{+35PnWsUFnNN^8lf0v68Oy&oSBa0E$V ze5J~88to5MDZA?699~0Him^%vH|v?chtS*Ws!BWhyEn^bjuBh5M+wg@h`3AQ cw&^?j6MgS4IM#l5)SHHef6(}&EB`Bh1GJK71^@s6 literal 3842 zcmd^?%T5$g5Qb}Q;yWB!uo4gwSD=IdDhbFa0~=!u%y4NlOykf9`fh|r;uZYH%XVd_Hn3nn?a)ScZi%Hfv^O?o^EPX*xG&pV zdv4F4*^+JAj(y{^Ze6Yo`)Kdu$~&GnS-les=(}Hd4Z$5-wa;woL^azeDs1)bFYF6K zYqo;O3eR7;3PMXZcdt9G7M2L|%(A;+cL+Vh<;40ia7DRYcz+HE1jrRpV_p*&!nF z$63@IaaFcvPRXqUT!EoEiMw~cG<%Xu1rqKRFp4w~aJ8hjgHT7ZDe-mb8W8O!t5`M} ztjgBRJpt|=SdiLxc+i9U&FGh9|IZv$NUelFF6qG*xY~f;wk`WWC*7iH2HNhpSVO7O zyjh))z5&gu%l(Qp>Nx07A`jIOXn!e02v|!Y!amv(`^`P?xq%*=(IC|pQx2Mm#Wop? zaijLey=o_a!^t>PhS7L4AbHDoC--rqkF#Y>vg5i&^y;GPmsmXHUEuiBT|Lj=5A8Un zViJHWkF=5jOaLV5s#-dX{vP4sfVZ=}?;@uYMqc~3{L6QHIy{PC)9lJ@k#y=HUqMdP z=#t_YRzBG-DDIK;Y5PHn(kQ#ieaMsI&5-MIikcQm zB9?pn%E>6AT}IUVSi2;S8K#g0d(Ee4XBw2{|D?DN(56#J`IN_F465Cx8|@w=tHXbj zU&@|NZLLZ7222|77ga@RWjf<2u>)ikm8K_A{31S!HRE05qRWsu=1qcb*PrKMEaNuH zxG7hoiSg&T9>yF6JSZ32L1c$;kl)UW(|FgMr)Xcsb Date: Wed, 23 Aug 2023 12:49:33 -0700 Subject: [PATCH 058/345] [release/8.0] Update dependencies from dotnet/roslyn (#90816) * Update dependencies from https://github.com/dotnet/roslyn build 20230818.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23418.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230818.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23418.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230818.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23418.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230818.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23418.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230818.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23418.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230819.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23419.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230821.15 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23421.15 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230821.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23421.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.9 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.11 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.11 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.12 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.12 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.13 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-1.23422.13 * Update dependencies from https://github.com/dotnet/roslyn build 20230822.14 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-1.23408.8 -> To Version 4.8.0-2.23422.14 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 270d5c0b3ad3e8..22b39bcd09b8bf 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 48270e734aa881c737b80c4fe0459e68aaf08ad6 - + https://github.com/dotnet/roslyn - 1fd4ff9d594b227baa3fc0962e2251323311ec19 + 93ce610622875b8e843f348e96496abd7056360d - + https://github.com/dotnet/roslyn - 1fd4ff9d594b227baa3fc0962e2251323311ec19 + 93ce610622875b8e843f348e96496abd7056360d - + https://github.com/dotnet/roslyn - 1fd4ff9d594b227baa3fc0962e2251323311ec19 + 93ce610622875b8e843f348e96496abd7056360d https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index f86168bdf919a3..6fa3fc30b30156 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-1.23408.8 - 4.8.0-1.23408.8 - 4.8.0-1.23408.8 + 4.8.0-2.23422.14 + 4.8.0-2.23422.14 + 4.8.0-2.23422.14 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 - 8.0.0-beta.23408.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 + 8.0.0-beta.23421.1 1.0.0-prerelease.23362.5 1.0.0-prerelease.23362.5 From 010980181b380f712bde42d3c1efab0e180414fc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 12:51:40 -0700 Subject: [PATCH 060/345] [release/8.0] [mono] Initialize module's image ALC for dynamic objects (#90912) * Use the image's ALC instead of the default one if exists * Init module's image ALC * Add runtime test for dynamic objects * Fix lint * Disable test on platforms that don't support dynamic code generation --------- Co-authored-by: Milos Kotlar --- src/mono/mono/metadata/sre.c | 2 + .../Loader/CustomAttributes/DynamicObjects.cs | 107 ++++++++++++++++++ .../CustomAttributes/DynamicObjects.csproj | 9 ++ src/tests/issues.targets | 7 ++ 4 files changed, 125 insertions(+) create mode 100644 src/tests/Loader/CustomAttributes/DynamicObjects.cs create mode 100644 src/tests/Loader/CustomAttributes/DynamicObjects.csproj diff --git a/src/mono/mono/metadata/sre.c b/src/mono/mono/metadata/sre.c index de94e8c4bf9a3b..3f47f9e84d008e 100644 --- a/src/mono/mono/metadata/sre.c +++ b/src/mono/mono/metadata/sre.c @@ -1289,6 +1289,7 @@ image_module_basic_init (MonoReflectionModuleBuilderHandle moduleb, MonoError *e * determined at assembly save time. */ /*image = (MonoDynamicImage*)ab->dynamic_assembly->assembly.image; */ + MonoAssemblyLoadContext *alc = mono_alc_get_default (); MonoStringHandle abname = MONO_HANDLE_NEW_GET (MonoString, ab, name); char *name = mono_string_handle_to_utf8 (abname, error); return_val_if_nok (error, FALSE); @@ -1300,6 +1301,7 @@ image_module_basic_init (MonoReflectionModuleBuilderHandle moduleb, MonoError *e } MonoDynamicAssembly *dynamic_assembly = MONO_HANDLE_GETVAL (ab, dynamic_assembly); image = mono_dynamic_image_create (dynamic_assembly, name, fqname); + image->image.alc = alc; MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoReflectionModule, moduleb), image, MonoImage*, &image->image); MONO_HANDLE_SETVAL (moduleb, dynamic_image, MonoDynamicImage*, image); diff --git a/src/tests/Loader/CustomAttributes/DynamicObjects.cs b/src/tests/Loader/CustomAttributes/DynamicObjects.cs new file mode 100644 index 00000000000000..5b232d83eba3bb --- /dev/null +++ b/src/tests/Loader/CustomAttributes/DynamicObjects.cs @@ -0,0 +1,107 @@ +using System; +using System.Resources; +using System.Reflection; +using System.Reflection.Emit; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +using Xunit; + +#nullable disable + +namespace DynamicObjects { + public class M { + public const string ObjectRequiredMessage = "some string"; + public static int Main() { + var instance = createObject(); + var attrs = instance.GetType().GetProperty("prop1").GetCustomAttributes(); + + Assert.True(attrs.Count() == 2); + Assert.Equal(attrs.ElementAt(0).ToString(), "System.ComponentModel.DataAnnotations.DisplayAttribute"); + Assert.Equal(attrs.ElementAt(1).ToString(), "System.ComponentModel.DataAnnotations.RequiredAttribute"); + Assert.Equal(typeof(RequiredAttribute), attrs.ElementAt(1).GetType()); + Assert.Equal(ObjectRequiredMessage, ((RequiredAttribute)attrs.ElementAt(1)).FormatErrorMessage("abc")); + + Console.WriteLine("Success"); + return 100; + } + + public static object createObject () { + var an = new AssemblyName { Name = "TempAssembly" ,Version = new Version(1, 0, 0, 0) }; + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run); + var moduleBuilder = assemblyBuilder.DefineDynamicModule("TempWorkflowAssembly.dll"); + var tb = moduleBuilder.DefineType("namespace.myclass" + , TypeAttributes.Public | + TypeAttributes.Class | + TypeAttributes.AnsiClass | + TypeAttributes.BeforeFieldInit + , typeof(object)); + + FieldBuilder fb = tb.DefineField("_prop1", + typeof(string), + FieldAttributes.Private); + + var pb = tb.DefineProperty("prop1", PropertyAttributes.HasDefault, typeof(string), null); + MethodAttributes getSetAttr = + MethodAttributes.Public | MethodAttributes.SpecialName | + MethodAttributes.HideBySig; + + // Define the "get" accessor method for prop1. + MethodBuilder custNameGetPropMthdBldr = + tb.DefineMethod("get_prop1", + getSetAttr, + typeof(string), + Type.EmptyTypes); + + ILGenerator custNameGetIL = custNameGetPropMthdBldr.GetILGenerator(); + + custNameGetIL.Emit(OpCodes.Ldarg_0); + custNameGetIL.Emit(OpCodes.Ldfld, fb); + custNameGetIL.Emit(OpCodes.Ret); + + // Define the "set" accessor method for prop1. + MethodBuilder custNameSetPropMthdBldr = + tb.DefineMethod("set_prop1", + getSetAttr, + null, + new Type[] { typeof(string) }); + + ILGenerator custNameSetIL = custNameSetPropMthdBldr.GetILGenerator(); + + custNameSetIL.Emit(OpCodes.Ldarg_0); + custNameSetIL.Emit(OpCodes.Ldarg_1); + custNameSetIL.Emit(OpCodes.Stfld, fb); + custNameSetIL.Emit(OpCodes.Ret); + + // Last, we must map the two methods created above to our PropertyBuilder to + // their corresponding behaviors, "get" and "set" respectively. + pb.SetGetMethod(custNameGetPropMthdBldr); + pb.SetSetMethod(custNameSetPropMthdBldr); + + + ///create display attribute + var dat = typeof(DisplayAttribute); + CustomAttributeBuilder CAB = new CustomAttributeBuilder(dat.GetConstructor(new Type[0]), + new object[0], + new PropertyInfo[1] { dat.GetProperty(nameof(DisplayAttribute.Name))}, + new object[] { "property 1"}); + pb.SetCustomAttribute(CAB); + + // //create required attribute + var rat = typeof(RequiredAttribute); + CustomAttributeBuilder CABR = new CustomAttributeBuilder(rat.GetConstructor(new Type[0]), + new object[0], + new PropertyInfo[2] { rat.GetProperty(nameof(RequiredAttribute.ErrorMessageResourceType)),rat.GetProperty(nameof(RequiredAttribute.ErrorMessageResourceName))}, + new object[] {typeof(ValidationErrors), "ObjectRequired" }); + pb.SetCustomAttribute(CABR); + + var objectType = tb.CreateType(); + return Activator.CreateInstance(objectType); + } + } + + public class ValidationErrors { + public static string ObjectRequired => M.ObjectRequiredMessage; + } + +} diff --git a/src/tests/Loader/CustomAttributes/DynamicObjects.csproj b/src/tests/Loader/CustomAttributes/DynamicObjects.csproj new file mode 100644 index 00000000000000..3e62bfd677e86a --- /dev/null +++ b/src/tests/Loader/CustomAttributes/DynamicObjects.csproj @@ -0,0 +1,9 @@ + + + Exe + + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 22178e4b3b506d..bdccec81ac1f49 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1177,6 +1177,10 @@ + + + Dynamic code generation is not supported on this platform + From 482bfb96ccd63da733bea3fe1f7f65fb4a3b6c67 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:43:00 -0700 Subject: [PATCH 065/345] [release/8.0] Only initialize listeners once (#90932) * Only initialize listeners once. * Add test * Second call --------- Co-authored-by: Chris R --- .../Microsoft.Extensions.Diagnostics.sln | 49 +++++++++++++++++++ .../src/Metrics/MetricsServiceExtensions.cs | 10 +++- .../tests/MetricsSubscriptionManagerTests.cs | 44 +++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/Microsoft.Extensions.Diagnostics.sln b/src/libraries/Microsoft.Extensions.Diagnostics/Microsoft.Extensions.Diagnostics.sln index 5e4931ef73fb1d..5b249c373b11c6 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/Microsoft.Extensions.Diagnostics.sln +++ b/src/libraries/Microsoft.Extensions.Diagnostics/Microsoft.Extensions.Diagnostics.sln @@ -59,6 +59,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Config EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Options", "..\Microsoft.Extensions.Options\ref\Microsoft.Extensions.Options.csproj", "{DBAB1C82-A3A0-4ADC-95BC-B87557C61C42}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Primitives", "..\Microsoft.Extensions.Primitives\ref\Microsoft.Extensions.Primitives.csproj", "{6BB43905-3DBD-47E4-A38F-2BE319300B15}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Primitives", "..\Microsoft.Extensions.Primitives\src\Microsoft.Extensions.Primitives.csproj", "{711B2905-FDC7-4D67-B40B-9DEFF042CB01}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Options", "..\Microsoft.Extensions.Options\src\Microsoft.Extensions.Options.csproj", "{B233AB55-788C-48B6-9557-098B8D0DDBFF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Configuration.Binder", "..\Microsoft.Extensions.Configuration.Binder\src\Microsoft.Extensions.Configuration.Binder.csproj", "{ECF14067-8633-4DDA-8EAE-124989F8E09E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Configuration.Binder", "..\Microsoft.Extensions.Configuration.Binder\ref\Microsoft.Extensions.Configuration.Binder.csproj", "{D835A0A8-C213-461F-8B41-6F2715DBEC43}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Options.ConfigurationExtensions", "..\Microsoft.Extensions.Options.ConfigurationExtensions\ref\Microsoft.Extensions.Options.ConfigurationExtensions.csproj", "{F2C0D619-8CAF-4F81-B681-3F75AF79661F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Configuration", "..\Microsoft.Extensions.Configuration\ref\Microsoft.Extensions.Configuration.csproj", "{57AF678A-3671-4B9E-9608-053E2197D0A4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -161,6 +175,34 @@ Global {DBAB1C82-A3A0-4ADC-95BC-B87557C61C42}.Debug|Any CPU.Build.0 = Debug|Any CPU {DBAB1C82-A3A0-4ADC-95BC-B87557C61C42}.Release|Any CPU.ActiveCfg = Release|Any CPU {DBAB1C82-A3A0-4ADC-95BC-B87557C61C42}.Release|Any CPU.Build.0 = Release|Any CPU + {6BB43905-3DBD-47E4-A38F-2BE319300B15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BB43905-3DBD-47E4-A38F-2BE319300B15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BB43905-3DBD-47E4-A38F-2BE319300B15}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BB43905-3DBD-47E4-A38F-2BE319300B15}.Release|Any CPU.Build.0 = Release|Any CPU + {711B2905-FDC7-4D67-B40B-9DEFF042CB01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {711B2905-FDC7-4D67-B40B-9DEFF042CB01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {711B2905-FDC7-4D67-B40B-9DEFF042CB01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {711B2905-FDC7-4D67-B40B-9DEFF042CB01}.Release|Any CPU.Build.0 = Release|Any CPU + {B233AB55-788C-48B6-9557-098B8D0DDBFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B233AB55-788C-48B6-9557-098B8D0DDBFF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B233AB55-788C-48B6-9557-098B8D0DDBFF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B233AB55-788C-48B6-9557-098B8D0DDBFF}.Release|Any CPU.Build.0 = Release|Any CPU + {ECF14067-8633-4DDA-8EAE-124989F8E09E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECF14067-8633-4DDA-8EAE-124989F8E09E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECF14067-8633-4DDA-8EAE-124989F8E09E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECF14067-8633-4DDA-8EAE-124989F8E09E}.Release|Any CPU.Build.0 = Release|Any CPU + {D835A0A8-C213-461F-8B41-6F2715DBEC43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D835A0A8-C213-461F-8B41-6F2715DBEC43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D835A0A8-C213-461F-8B41-6F2715DBEC43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D835A0A8-C213-461F-8B41-6F2715DBEC43}.Release|Any CPU.Build.0 = Release|Any CPU + {F2C0D619-8CAF-4F81-B681-3F75AF79661F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2C0D619-8CAF-4F81-B681-3F75AF79661F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2C0D619-8CAF-4F81-B681-3F75AF79661F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2C0D619-8CAF-4F81-B681-3F75AF79661F}.Release|Any CPU.Build.0 = Release|Any CPU + {57AF678A-3671-4B9E-9608-053E2197D0A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57AF678A-3671-4B9E-9608-053E2197D0A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57AF678A-3671-4B9E-9608-053E2197D0A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {57AF678A-3671-4B9E-9608-053E2197D0A4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -190,6 +232,13 @@ Global {A2853038-B04A-4BAA-B0B4-0481457003B8} = {A447D0CB-601B-479E-A2B2-76E48F5D4D61} {A77E804D-4576-4962-A248-92E538ED997C} = {A447D0CB-601B-479E-A2B2-76E48F5D4D61} {DBAB1C82-A3A0-4ADC-95BC-B87557C61C42} = {9BF048D0-411D-4C2A-8C32-3A3255501D27} + {6BB43905-3DBD-47E4-A38F-2BE319300B15} = {9BF048D0-411D-4C2A-8C32-3A3255501D27} + {711B2905-FDC7-4D67-B40B-9DEFF042CB01} = {A447D0CB-601B-479E-A2B2-76E48F5D4D61} + {B233AB55-788C-48B6-9557-098B8D0DDBFF} = {A447D0CB-601B-479E-A2B2-76E48F5D4D61} + {ECF14067-8633-4DDA-8EAE-124989F8E09E} = {A447D0CB-601B-479E-A2B2-76E48F5D4D61} + {D835A0A8-C213-461F-8B41-6F2715DBEC43} = {9BF048D0-411D-4C2A-8C32-3A3255501D27} + {F2C0D619-8CAF-4F81-B681-3F75AF79661F} = {9BF048D0-411D-4C2A-8C32-3A3255501D27} + {57AF678A-3671-4B9E-9608-053E2197D0A4} = {9BF048D0-411D-4C2A-8C32-3A3255501D27} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7D279EE5-E38F-4125-AE82-6ADE52D72F26} diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/src/Metrics/MetricsServiceExtensions.cs b/src/libraries/Microsoft.Extensions.Diagnostics/src/Metrics/MetricsServiceExtensions.cs index 79a08c78b82e7c..47fa1e0dee8193 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/src/Metrics/MetricsServiceExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Diagnostics/src/Metrics/MetricsServiceExtensions.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Diagnostics.Metrics; using Microsoft.Extensions.Diagnostics.Metrics.Configuration; +using Microsoft.Extensions.Options; using System; using System.Diagnostics.Metrics; @@ -32,7 +33,9 @@ public static IServiceCollection AddMetrics(this IServiceCollection services) services.TryAddSingleton(); // Make sure the subscription manager is started when the host starts. // The host will trigger options validation. - services.AddOptions().Configure((_, manager) => manager.Initialize()).ValidateOnStart(); + services.AddOptions().ValidateOnStart(); + // Make sure this is only registered/run once. + services.TryAddSingleton, SubscriptionActivator>(); services.TryAddSingleton(); @@ -66,5 +69,10 @@ private sealed class MetricsBuilder(IServiceCollection services) : IMetricsBuild } private sealed class NoOpOptions { } + + private sealed class SubscriptionActivator(MetricsSubscriptionManager manager) : IConfigureOptions + { + public void Configure(NoOpOptions options) => manager.Initialize(); + } } } diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs new file mode 100644 index 00000000000000..60049f6820e963 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics.Metrics; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.Metrics; +using Microsoft.Extensions.Options; +using Xunit; + +namespace Microsoft.Extensions.Diagnostics.Tests +{ + public class MetricsSubscriptionManagerTests + { + [Fact] + public void AddMetrics_InitializesListeners() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddMetrics(); // Duplicate call, should not add things twice. + serviceCollection.AddMetrics(l => l.AddListener()); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Make sure the subscription manager is started. + serviceProvider.GetRequiredService().Validate(); + + var listeners = serviceProvider.GetRequiredService>(); + + var listener = Assert.Single(listeners); + var fakeListener = Assert.IsType(listener); + Assert.Equal(1, fakeListener.InitializeCount); + } + + private class FakeListener : IMetricsListener + { + public string Name => "Fake"; + public int InitializeCount { get; private set; } + public MeasurementHandlers GetMeasurementHandlers() => new MeasurementHandlers(); + public void Initialize(IObservableInstrumentsSource source) => InitializeCount++; + public bool InstrumentPublished(Instrument instrument, out object? userState) => throw new NotImplementedException(); + public void MeasurementsCompleted(Instrument instrument, object? userState) => throw new NotImplementedException(); + } + } +} From eb124c5b6c07f91f8f5eb846e1db235fe84030a6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:44:09 -0700 Subject: [PATCH 066/345] [release/8.0] Fix Type.ContainsGenericParameters for function pointers (#90963) * Fix Type.ContainsGenericParameters for function pointers Fixes #84916 * Fix System.Reflection.MetadataLoadContext * Fix Mono * Update test --------- Co-authored-by: Jan Kotas --- src/coreclr/vm/typedesc.cpp | 40 +++++++++++++++++++ src/coreclr/vm/typedesc.h | 4 ++ src/coreclr/vm/typehandle.cpp | 24 ++--------- .../tests/System/FunctionPointerTests.cs | 19 +++++++++ .../Types/RoFunctionPointerType.cs | 18 ++++++++- .../src/System/RuntimeType.Mono.cs | 10 +++++ 6 files changed, 94 insertions(+), 21 deletions(-) diff --git a/src/coreclr/vm/typedesc.cpp b/src/coreclr/vm/typedesc.cpp index 6c3226882503c6..95e86ccc961691 100644 --- a/src/coreclr/vm/typedesc.cpp +++ b/src/coreclr/vm/typedesc.cpp @@ -104,6 +104,31 @@ BOOL TypeDesc::IsSharedByGenericInstantiations() return FALSE; } +BOOL TypeDesc::ContainsGenericVariables(BOOL methodOnly) +{ + if (IsGenericVariable()) + { + if (!methodOnly) + return TRUE; + + PTR_TypeVarTypeDesc pTyVar = dac_cast(this); + return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef; + } + + if (HasTypeParam()) + { + return GetRootTypeParam().ContainsGenericVariables(methodOnly); + } + + if (IsFnPtr()) + { + return dac_cast(this)->ContainsGenericVariables(methodOnly); + } + + return FALSE; +} + + PTR_BaseDomain TypeDesc::GetDomain() { CONTRACTL @@ -1670,6 +1695,21 @@ FnPtrTypeDesc::IsSharedByGenericInstantiations() return FALSE; } // FnPtrTypeDesc::IsSharedByGenericInstantiations +BOOL +FnPtrTypeDesc::ContainsGenericVariables(BOOL methodOnly) +{ + LIMITED_METHOD_DAC_CONTRACT; + + for (DWORD i = 0; i <= m_NumArgs; i++) + { + if (m_RetAndArgTypes[i].ContainsGenericVariables(methodOnly)) + { + return TRUE; + } + } + return FALSE; +} // FnPtrTypeDesc::ContainsGenericVariables + #ifndef DACCESS_COMPILE // Returns TRUE if all return and argument types are externally visible. diff --git a/src/coreclr/vm/typedesc.h b/src/coreclr/vm/typedesc.h index 51614c3b110778..b86845c81e21c0 100644 --- a/src/coreclr/vm/typedesc.h +++ b/src/coreclr/vm/typedesc.h @@ -182,6 +182,8 @@ class TypeDesc BOOL IsSharedByGenericInstantiations(); + BOOL ContainsGenericVariables(BOOL methodOnly); + protected: // See methodtable.h for details of the flags with the same name there enum @@ -527,6 +529,8 @@ class FnPtrTypeDesc : public TypeDesc BOOL IsSharedByGenericInstantiations(); + BOOL ContainsGenericVariables(BOOL methodOnly); + #ifndef DACCESS_COMPILE // Returns TRUE if all return and argument types are externally visible. BOOL IsExternallyVisible() const; diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp index 59eed8b5030d86..053cc759217c76 100644 --- a/src/coreclr/vm/typehandle.cpp +++ b/src/coreclr/vm/typehandle.cpp @@ -138,26 +138,10 @@ BOOL TypeHandle::ContainsGenericVariables(BOOL methodOnly /*=FALSE*/) const STATIC_CONTRACT_NOTHROW; SUPPORTS_DAC; - if (HasTypeParam()) - { - return GetTypeParam().ContainsGenericVariables(methodOnly); - } - - if (IsGenericVariable()) - { - if (!methodOnly) - return TRUE; - - PTR_TypeVarTypeDesc pTyVar = dac_cast(AsTypeDesc()); - return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef; - } - else if (HasInstantiation()) - { - if (GetMethodTable()->ContainsGenericVariables(methodOnly)) - return TRUE; - } - - return FALSE; + if (IsTypeDesc()) + return AsTypeDesc()->ContainsGenericVariables(methodOnly); + else + return AsMethodTable()->ContainsGenericVariables(methodOnly); } //@GENERICS: diff --git a/src/libraries/Common/tests/System/FunctionPointerTests.cs b/src/libraries/Common/tests/System/FunctionPointerTests.cs index 925c8683f8f7f4..8a344e01e78955 100644 --- a/src/libraries/Common/tests/System/FunctionPointerTests.cs +++ b/src/libraries/Common/tests/System/FunctionPointerTests.cs @@ -173,6 +173,22 @@ public static unsafe void RequiredModifiers() Assert.Equal(typeof(Runtime.InteropServices.OutAttribute).Project(), parameters[1].GetRequiredCustomModifiers()[0]); } + [Fact] + public static unsafe void GenericFunctionPointer() + { + Type t = typeof(FunctionPointerHolder).Project(); + + MethodInfo m1 = t.GetMethod(nameof(FunctionPointerHolder.GenericReturnValue), Bindings); + Type fcnPtr1 = m1.ReturnType; + Assert.True(fcnPtr1.IsFunctionPointer); + Assert.True(fcnPtr1.ContainsGenericParameters); + + MethodInfo m2 = t.GetMethod(nameof(FunctionPointerHolder.GenericArgument), Bindings); + Type fcnPtr2 = m2.GetParameters()[1].ParameterType; + Assert.True(fcnPtr2.IsFunctionPointer); + Assert.True(fcnPtr2.ContainsGenericParameters); + } + [Theory] [InlineData(nameof(FunctionPointerHolder.MethodReturnValue1), "MethodReturnValue1()", @@ -278,6 +294,9 @@ private unsafe class FunctionPointerHolder public delegate* unmanaged[Stdcall, MemberFunction] SeveralArguments() => default; public delegate* RequiredModifiers() => default; + public delegate* GenericReturnValue() => default; + public bool GenericArgument(int x, delegate* fptr) => default; + public class MyClass { } public struct MyStruct { } } diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs index 73cd87437551f6..426ab7085d9fdd 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoFunctionPointerType.cs @@ -147,7 +147,23 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj) public sealed override bool IsGenericParameter => false; public sealed override bool IsGenericTypeParameter => false; public sealed override bool IsGenericMethodParameter => false; - public sealed override bool ContainsGenericParameters => IsGenericTypeDefinition; + + public sealed override bool ContainsGenericParameters + { + get + { + if (_returnType.ContainsGenericParameters) + return true; + + foreach (Type parameterType in _parameterTypes) + { + if (parameterType.ContainsGenericParameters) + return true; + } + + return false; + } + } protected sealed override TypeCode GetTypeCodeImpl() => TypeCode.Object; diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index e7feb145b18846..5924d5c0640df7 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -2048,6 +2048,16 @@ public override bool ContainsGenericParameters if (HasElementType) return GetElementType().ContainsGenericParameters; + if (IsFunctionPointer) + { + if (GetFunctionPointerReturnType().ContainsGenericParameters) + return true; + + foreach (Type arg in GetFunctionPointerParameterTypes()) + if (arg.ContainsGenericParameters) + return true; + } + return false; } } From ac16ae11a6e1f613aa363656507e682222d156fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:53:41 -0700 Subject: [PATCH 067/345] [release/8.0] Support assignment to multiple refs in trim analyzer (#90936) * Support assignment to multiple refs * Add support for assigning to arrays * Fix tests for illink/nativeaot * Remove ref local test, add issue links --------- Co-authored-by: Sven Boemer --- .../DataFlow/CapturedReferenceValue.cs | 21 +-- .../DataFlow/LValueFlowCaptureProvider.cs | 28 +++- .../DataFlow/LocalDataFlowVisitor.cs | 131 +++++++++++---- .../DataFlow/LocalStateLattice.cs | 12 +- .../TrimAnalysis/TrimAnalysisVisitor.cs | 13 +- .../src/ILLink.Shared/DataFlow/ValueSet.cs | 2 + .../MethodWithUnmanagedConstraint.cs | 1 - .../DataFlow/ByRefDataflow.cs | 155 +++++++++++++++++- .../TestCasesRunner/TestCaseCompiler.cs | 3 - 9 files changed, 293 insertions(+), 73 deletions(-) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/CapturedReferenceValue.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/CapturedReferenceValue.cs index d7033d9d799615..37e22e2228175c 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/CapturedReferenceValue.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/CapturedReferenceValue.cs @@ -10,7 +10,7 @@ namespace ILLink.RoslynAnalyzer.DataFlow { public readonly struct CapturedReferenceValue : IEquatable { - public readonly IOperation? Reference; + public readonly IOperation Reference; public CapturedReferenceValue (IOperation operation) { @@ -48,23 +48,4 @@ public override bool Equals (object obj) public override int GetHashCode () => Reference?.GetHashCode () ?? 0; } - - - public struct CapturedReferenceLattice : ILattice - { - public CapturedReferenceValue Top => default; - - public CapturedReferenceValue Meet (CapturedReferenceValue left, CapturedReferenceValue right) - { - if (left.Equals (right)) - return left; - if (left.Reference == null) - return right; - if (right.Reference == null) - return left; - // Both non-null and different shouldn't happen. - // We assume that a flow capture can capture only a single property. - throw new InvalidOperationException (); - } - } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LValueFlowCaptureProvider.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LValueFlowCaptureProvider.cs index 610a4cfd44606c..446379586e5b29 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LValueFlowCaptureProvider.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LValueFlowCaptureProvider.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -#nullable disable +#nullable enable using System.Collections.Generic; using System.Collections.Immutable; @@ -15,7 +15,7 @@ namespace ILLink.RoslynAnalyzer.DataFlow { - // Copied from https://github.com/dotnet/roslyn/blob/c8ebc8682889b395fcb84c85bf4ff54577377d26/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/LValueFlowCaptureProvider.cs + // Adapted from https://github.com/dotnet/roslyn/blob/c8ebc8682889b395fcb84c85bf4ff54577377d26/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/LValueFlowCaptureProvider.cs /// /// Helper class to detect s that are l-value captures. /// L-value captures are essentially captures of a symbol's location/address. @@ -38,6 +38,22 @@ namespace ILLink.RoslynAnalyzer.DataFlow /// internal static class LValueFlowCapturesProvider { + static bool IsLValueFlowCapture (IFlowCaptureReferenceOperation flowCaptureReference, out IAssignmentOperation? assignment) + { + assignment = flowCaptureReference.Parent as IAssignmentOperation; + if (assignment?.Target == flowCaptureReference) + return true; + + if (flowCaptureReference.Parent is IArrayElementReferenceOperation arrayAlementRef) { + assignment = arrayAlementRef.Parent as IAssignmentOperation; + if (assignment?.Target == arrayAlementRef) + return true; + } + + assignment = null; + return flowCaptureReference.IsInLeftOfDeconstructionAssignment (out _); + } + public static ImmutableDictionary CreateLValueFlowCaptures (ControlFlowGraph cfg) { // This method identifies flow capture reference operations that are target of an assignment @@ -47,15 +63,13 @@ public static ImmutableDictionary CreateLValueFlowCa // the flow graph. Specifically, for an ICoalesceOperation a flow capture acts // as both an r-value and l-value flow capture. - ImmutableDictionary.Builder lvalueFlowCaptureIdBuilder = null; + ImmutableDictionary.Builder? lvalueFlowCaptureIdBuilder = null; var rvalueFlowCaptureIds = new HashSet (); foreach (var flowCaptureReference in cfg.DescendantOperations (OperationKind.FlowCaptureReference)) { - if (flowCaptureReference.Parent is IAssignmentOperation assignment && - assignment.Target == flowCaptureReference || - flowCaptureReference.IsInLeftOfDeconstructionAssignment (out _)) { + if (IsLValueFlowCapture (flowCaptureReference, out IAssignmentOperation? assignment)) { lvalueFlowCaptureIdBuilder ??= ImmutableDictionary.CreateBuilder (); - var captureKind = flowCaptureReference.Parent.IsAnyCompoundAssignment () || rvalueFlowCaptureIds.Contains (flowCaptureReference.Id) + var captureKind = assignment?.IsAnyCompoundAssignment () == true || rvalueFlowCaptureIds.Contains (flowCaptureReference.Id) ? FlowCaptureKind.LValueAndRValueCapture : FlowCaptureKind.LValueCapture; lvalueFlowCaptureIdBuilder.Add (flowCaptureReference.Id, captureKind); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs index 6143e03ab935da..80ce7a66f4d231 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs @@ -96,7 +96,7 @@ public void Transfer (BlockProxy block, LocalDataFlowState state) + void SetLocal (ILocalReferenceOperation operation, TValue value, LocalDataFlowState state, bool merge = false) { var local = new LocalKey (operation.Local); if (IsReferenceToCapturedVariable (operation)) @@ -149,27 +149,14 @@ void SetLocal (ILocalReferenceOperation operation, TValue value, LocalDataFlowSt if (InterproceduralState.TrySetHoistedLocal (local, value)) return; - state.Set (local, value); + var newValue = merge + ? state.Lattice.Lattice.ValueLattice.Meet (state.Get (local), value) + : value; + state.Set (local, newValue); } - public override TValue VisitSimpleAssignment (ISimpleAssignmentOperation operation, LocalDataFlowState state) + TValue ProcessSingleTargetAssignment (IOperation targetOperation, ISimpleAssignmentOperation operation, LocalDataFlowState state, bool merge) { - var targetOperation = operation.Target; - if (targetOperation is IFlowCaptureReferenceOperation flowCaptureReference) { - Debug.Assert (IsLValueFlowCapture (flowCaptureReference.Id)); - Debug.Assert (!flowCaptureReference.GetValueUsageInfo (Method).HasFlag (ValueUsageInfo.Read)); - var capturedReference = state.Current.CapturedReferences.Get (flowCaptureReference.Id).Reference; - targetOperation = capturedReference; - if (targetOperation == null) - throw new InvalidOperationException (); - - // Note: technically we should avoid visiting the target operation below when assigning to a flow capture reference, - // because this should be done when the capture is created. For example, a flow capture used as both an LValue and a RValue - // should only evaluate the expression that computes the object instance of a property reference once. - // However, we just visit the instance again below for simplicity. This could be generalized if we encounter a dataflow - // behavior where this makes a difference. - } - switch (targetOperation) { case IFieldReferenceOperation: case IParameterReferenceOperation: { @@ -237,17 +224,52 @@ public override TValue VisitSimpleAssignment (ISimpleAssignmentOperation operati // TODO: when setting a property in an attribute, target is an IPropertyReference. case ILocalReferenceOperation localRef: { TValue value = Visit (operation.Value, state); - SetLocal (localRef, value, state); + SetLocal (localRef, value, state, merge); return value; } case IArrayElementReferenceOperation arrayElementRef: { if (arrayElementRef.Indices.Length != 1) break; - TValue arrayRef = Visit (arrayElementRef.ArrayReference, state); - TValue index = Visit (arrayElementRef.Indices[0], state); - TValue value = Visit (operation.Value, state); - HandleArrayElementWrite (arrayRef, index, value, operation); + // Similarly to VisitSimpleAssignment, this needs to handle cases where the array reference + // is a captured variable, even if the target of the assignment (the array element reference) is not. + + TValue arrayRef; + TValue index; + TValue value; + if (arrayElementRef.ArrayReference is not IFlowCaptureReferenceOperation captureReference) { + arrayRef = Visit (arrayElementRef.ArrayReference, state); + index = Visit (arrayElementRef.Indices[0], state); + value = Visit (operation.Value, state); + HandleArrayElementWrite (arrayRef, index, value, operation, merge: merge); + return value; + } + + index = Visit (arrayElementRef.Indices[0], state); + value = Visit (operation.Value, state); + + var capturedReferences = state.Current.CapturedReferences.Get (captureReference.Id); + if (!capturedReferences.HasMultipleValues) { + // Single captured reference. Treat this as an overwriting assignment, + // unless the caller already told us to merge values because this is an + // assignment to one of multiple captured array element references. + var enumerator = capturedReferences.GetEnumerator (); + enumerator.MoveNext (); + var capture = enumerator.Current; + arrayRef = Visit (capture.Reference, state); + HandleArrayElementWrite (arrayRef, index, value, operation, merge: merge); + return value; + } + + // The capture id may have captured multiple references, as in: + // (b ? arr1 : arr2)[0] = value; + // We treat this as possible write to each of the captured references, + // which requires merging with the previous values of each. + + foreach (var capture in state.Current.CapturedReferences.Get (captureReference.Id)) { + arrayRef = Visit (capture.Reference, state); + HandleArrayElementWrite (arrayRef, index, value, operation, merge: true); + } return value; } case IDiscardOperation: @@ -293,8 +315,50 @@ public override TValue VisitSimpleAssignment (ISimpleAssignmentOperation operati return Visit (operation.Value, state); } - // Similar to VisitLocalReference - public override TValue VisitFlowCaptureReference (IFlowCaptureReferenceOperation operation, LocalDataFlowState state) + public override TValue VisitSimpleAssignment (ISimpleAssignmentOperation operation, LocalDataFlowState state) + { + var targetOperation = operation.Target; + if (targetOperation is not IFlowCaptureReferenceOperation flowCaptureReference) + return ProcessSingleTargetAssignment (targetOperation, operation, state, merge: false); + + // Note: technically we should avoid visiting the target operation in ProcessNonCapturedAssignment when assigning + // to a flow capture reference, because this should be done when the capture is created. + // For example, a flow capture used as both an LValue and a RValue should only evaluate the expression that + // computes the object instance of a property reference once. However, we just visit the instance again below + // for simplicity. This could be generalized if we encounter a dataflow behavior where this makes a difference. + + Debug.Assert (IsLValueFlowCapture (flowCaptureReference.Id)); + Debug.Assert (!flowCaptureReference.GetValueUsageInfo (Method).HasFlag (ValueUsageInfo.Read)); + var capturedReferences = state.Current.CapturedReferences.Get (flowCaptureReference.Id); + if (!capturedReferences.HasMultipleValues) { + // Single captured reference. Treat this as an overwriting assignment. + var enumerator = capturedReferences.GetEnumerator (); + enumerator.MoveNext (); + targetOperation = enumerator.Current.Reference; + return ProcessSingleTargetAssignment (targetOperation, operation, state, merge: false); + } + + // The capture id may have captured multiple references, as in: + // (b ? ref v1 : ref v2) = value; + // We treat this as a possible write to each of the captured references, + // which requires merging with the previous values of each. + + // Note: technically this should only visit the RHS of the assignment once. + // For now we visit the RHS in ProcessSingleTargetAssignment for simplicity, and + // rely on the warning deduplication to prevent this from producing multiple warnings + // if the RHS has dataflow warnings. + + TValue value = TopValue; + foreach (var capturedReference in capturedReferences) { + targetOperation = capturedReference.Reference; + var singleValue = ProcessSingleTargetAssignment (targetOperation, operation, state, merge: true); + value = LocalStateLattice.Lattice.ValueLattice.Meet (value, singleValue); + } + + return value; + } + + TValue GetFlowCaptureValue (IFlowCaptureReferenceOperation operation, LocalDataFlowState state) { if (!operation.GetValueUsageInfo (Method).HasFlag (ValueUsageInfo.Read)) { // There are known cases where this assert doesn't hold, because LValueFlowCaptureProvider @@ -304,10 +368,21 @@ public override TValue VisitFlowCaptureReference (IFlowCaptureReferenceOperation return TopValue; } - Debug.Assert (IsRValueFlowCapture (operation.Id)); + // This assert is incorrect for cases like (b ? arr1 : arr2)[0] = v; + // Here the ValueUsageInfo shows that the value usage is for reading (this is probably wrong!) + // but the value is actually an LValueFlowCapture. + // Let's just disable the assert for now. + // Debug.Assert (IsRValueFlowCapture (operation.Id)); + return state.Get (new LocalKey (operation.Id)); } + // Similar to VisitLocalReference + public override TValue VisitFlowCaptureReference (IFlowCaptureReferenceOperation operation, LocalDataFlowState state) + { + return GetFlowCaptureValue (operation, state); + } + // Similar to VisitSimpleAssignment when assigning to a local, but for values which are captured without a // corresponding local variable. The "flow capture" is like a local assignment, and the "flow capture reference" // is like a local reference. diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalStateLattice.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalStateLattice.cs index 6b5677df686a52..84270212ec5e5f 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalStateLattice.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalStateLattice.cs @@ -43,22 +43,22 @@ public struct LocalState : IEquatable> // Stores any operations which are captured by reference in a FlowCaptureOperation. // Only stores captures which are assigned through. Captures of the values of operations // are tracked as part of the dictionary of values, keyed by LocalKey. - public DefaultValueDictionary CapturedReferences; + public DefaultValueDictionary> CapturedReferences; public LocalState (TValue defaultValue) : this (new DefaultValueDictionary (defaultValue), - new DefaultValueDictionary (default (CapturedReferenceValue))) + new DefaultValueDictionary> (default (ValueSet))) { } - public LocalState (DefaultValueDictionary dictionary, DefaultValueDictionary capturedReferences) + public LocalState (DefaultValueDictionary dictionary, DefaultValueDictionary> capturedReferences) { Dictionary = dictionary; CapturedReferences = capturedReferences; } public LocalState (DefaultValueDictionary dictionary) - : this (dictionary, new DefaultValueDictionary (default (CapturedReferenceValue))) + : this (dictionary, new DefaultValueDictionary> (default (ValueSet))) { } @@ -83,12 +83,12 @@ public override int GetHashCode () where TValueLattice : ILattice { public readonly DictionaryLattice Lattice; - public readonly DictionaryLattice CapturedReferenceLattice; + public readonly DictionaryLattice, ValueSetLattice> CapturedReferenceLattice; public LocalStateLattice (TValueLattice valueLattice) { Lattice = new DictionaryLattice (valueLattice); - CapturedReferenceLattice = new DictionaryLattice (default (CapturedReferenceLattice)); + CapturedReferenceLattice = new DictionaryLattice, ValueSetLattice> (default (ValueSetLattice)); Top = new (Lattice.Top); } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index dccf85a2c5b240..04c7b06fa048e6 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -219,7 +219,7 @@ public override MultiValue HandleArrayElementRead (MultiValue arrayValue, MultiV return result.Equals (TopValue) ? UnknownValue.Instance : result; } - public override void HandleArrayElementWrite (MultiValue arrayValue, MultiValue indexValue, MultiValue valueToWrite, IOperation operation) + public override void HandleArrayElementWrite (MultiValue arrayValue, MultiValue indexValue, MultiValue valueToWrite, IOperation operation, bool merge) { int? index = indexValue.AsConstInt (); foreach (var arraySingleValue in arrayValue) { @@ -227,12 +227,11 @@ public override void HandleArrayElementWrite (MultiValue arrayValue, MultiValue if (index == null) { // Reset the array to all unknowns - since we don't know which index is being assigned arr.IndexValues.Clear (); - } else { - if (arr.IndexValues.TryGetValue (index.Value, out _)) { - arr.IndexValues[index.Value] = ArrayValue.SanitizeArrayElementValue(valueToWrite); - } else if (arr.IndexValues.Count < MaxTrackedArrayValues) { - arr.IndexValues[index.Value] = ArrayValue.SanitizeArrayElementValue(valueToWrite); - } + } else if (arr.IndexValues.TryGetValue (index.Value, out _) || arr.IndexValues.Count < MaxTrackedArrayValues) { + var sanitizedValue = ArrayValue.SanitizeArrayElementValue(valueToWrite); + arr.IndexValues[index.Value] = merge + ? _multiValueLattice.Meet (arr.IndexValues[index.Value], sanitizedValue) + : sanitizedValue; } } } diff --git a/src/tools/illink/src/ILLink.Shared/DataFlow/ValueSet.cs b/src/tools/illink/src/ILLink.Shared/DataFlow/ValueSet.cs index 2fb1fc3f21746e..d538d358e8cea3 100644 --- a/src/tools/illink/src/ILLink.Shared/DataFlow/ValueSet.cs +++ b/src/tools/illink/src/ILLink.Shared/DataFlow/ValueSet.cs @@ -132,6 +132,8 @@ public void Reset () public static implicit operator ValueSet (TValue value) => new (value); + public bool HasMultipleValues => _values is EnumerableValues; + public override bool Equals (object? obj) => obj is ValueSet other && Equals (other); public bool Equals (ValueSet other) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs index e2d3e86fb6679d..713ed17db49d54 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Attributes/OnlyKeepUsed/MethodWithUnmanagedConstraint.cs @@ -4,7 +4,6 @@ namespace Mono.Linker.Tests.Cases.Attributes.OnlyKeepUsed { [SetupCSharpCompilerToUse ("csc")] - [SetupCompileArgument ("/langversion:7.3")] [SetupLinkerArgument ("--used-attrs-only", "true")] public class MethodWithUnmanagedConstraint { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs index b7c71da382b731..8348f5d6e68fbd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ByRefDataflow.cs @@ -5,10 +5,10 @@ using System.Diagnostics.CodeAnalysis; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.Expectations.Helpers; namespace Mono.Linker.Tests.Cases.DataFlow { - [SetupCompileArgument ("/langversion:7.3")] [SetupCompileArgument ("/unsafe")] [Kept] [ExpectedNoWarnings] @@ -35,6 +35,7 @@ public static void Main () PointerDereference.Test (); MultipleOutRefsToField.Test (); + MultipleRefCaptures.Test (); } [Kept] @@ -187,5 +188,157 @@ public static void Test () TwoOutRefs (out _publicMethodsField, out _publicPropertiesField); } } + + [Kept] + class MultipleRefCaptures + { + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + static Type _publicMethodsField; + + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] + static Type _publicPropertiesField; + + static Type Prop { get; set; } + + [Kept] + [ExpectedWarning ("IL2074", nameof (_publicMethodsField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (_publicPropertiesField), nameof (GetUnknownType))] + static void TestFieldAssignment (bool b = true) + { + (b ? ref _publicMethodsField : ref _publicPropertiesField) = GetUnknownType (); + } + + [Kept] + [ExpectedWarning ("IL2072", nameof (publicMethodsParameter), nameof (GetUnknownType))] + [ExpectedWarning ("IL2072", nameof (publicPropertiesParameter), nameof (GetUnknownType))] + static void TestParameterAssignment ( + bool b = true, + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + Type publicMethodsParameter = null, + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] + Type publicPropertiesParameter = null) + { + (b ? ref publicMethodsParameter : ref publicPropertiesParameter) = GetUnknownType (); + } + + [Kept] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll))] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll))] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll))] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll))] + static void TestLocalAssignment (bool b = true) + { + var local1 = GetUnknownType (); + var local2 = GetTypeWithPublicFields (); + (b ? ref local1 : ref local2) = GetTypeWithPublicConstructors (); + local1.RequiresAll (); + local2.RequiresAll (); + } + + [Kept] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + // ILLink/ILCompiler produce different warning code: https://github.com/dotnet/linker/issues/2737 + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2062", nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + static void TestArrayElementReferenceAssignment (bool b = true) + { + var arr1 = new Type[] { GetUnknownType () }; + var arr2 = new Type[] { GetTypeWithPublicConstructors () }; + (b ? ref arr1[0] : ref arr2[0]) = GetTypeWithPublicFields (); + arr1[0].RequiresAll (); + arr2[0].RequiresAll (); + } + + [Kept] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll))] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicConstructors), nameof (DataFlowTypeExtensions.RequiresAll))] + // ILLink/ILCompiler analysis hole: https://github.com/dotnet/runtime/issues/90335 + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2072", nameof (GetTypeWithPublicFields), nameof (DataFlowTypeExtensions.RequiresAll), ProducedBy = Tool.Analyzer)] + static void TestArrayElementAssignment (bool b = true) + { + var arr1 = new Type[] { GetUnknownType () }; + var arr2 = new Type[] { GetTypeWithPublicConstructors () }; + (b ? arr1 : arr2)[0] = GetTypeWithPublicFields (); + arr1[0].RequiresAll (); + arr2[0].RequiresAll (); + } + + [Kept] + [ExpectedWarning ("IL2074", nameof (_publicMethodsField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (_publicPropertiesField), nameof (GetUnknownType))] + static void TestNullCoalescingAssignment (bool b = true) + { + (b ? ref _publicMethodsField : ref _publicPropertiesField) ??= GetUnknownType (); + } + + [Kept] + [ExpectedWarning ("IL2074", nameof (_publicMethodsField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (_publicMethodsField), nameof (GetTypeWithPublicConstructors))] + [ExpectedWarning ("IL2074", nameof (_publicPropertiesField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (_publicPropertiesField), nameof (GetTypeWithPublicConstructors))] + static void TestNullCoalescingAssignmentComplex (bool b = true) + { + (b ? ref _publicMethodsField : ref _publicPropertiesField) ??= GetUnknownType () ?? GetTypeWithPublicConstructors (); + } + + [Kept] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DynamicallyAccessedMemberTypes.PublicConstructors), nameof (type))] + [ExpectedWarning ("IL2074", nameof (_publicMethodsField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (_publicPropertiesField), nameof (GetUnknownType))] + static void TestDataFlowOnRightHandOfAssignment ( + bool b = true, + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] Type type = null) + { + (b ? ref _publicMethodsField : ref _publicPropertiesField) = (type = GetUnknownType ()); + } + + [Kept] + [ExpectedWarning ("IL2074", nameof (_publicMethodsField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2074", nameof (_publicPropertiesField), nameof (GetUnknownType))] + [ExpectedWarning ("IL2072", nameof (GetUnknownType), nameof (DataFlowTypeExtensions.RequiresAll))] + static void TestReturnValue (bool b = true) + { + var value = (b ? ref _publicMethodsField : ref _publicPropertiesField) = GetUnknownType (); + value.RequiresAll (); + } + + [Kept] + public static void Test () + { + TestFieldAssignment (); + TestParameterAssignment (); + TestLocalAssignment (); + TestArrayElementReferenceAssignment (); + TestArrayElementAssignment (); + TestNullCoalescingAssignment (); + TestNullCoalescingAssignmentComplex (); + TestDataFlowOnRightHandOfAssignment (); + TestReturnValue (); + } + } + + [Kept] + static Type GetUnknownType () => null; + + [Kept] + [return: KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)] + static Type GetTypeWithPublicConstructors () => null; + + [Kept] + [return: KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] + static Type GetTypeWithPublicFields () => null; } } diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs index aba20b96f3b157..ec427ebdbc4858 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs @@ -267,9 +267,6 @@ protected virtual NPath CompileCSharpAssemblyWithRoslyn (CompilerOptions options emitPdb = true; debugType = DebugInformationFormat.Embedded; break; - case "/langversion:7.3": - languageVersion = LanguageVersion.CSharp7_3; - break; default: var splitIndex = option.IndexOf (":"); if (splitIndex != -1 && option[..splitIndex] == "/main") { From 303f1d3908c9dace1ee0d4a23682730ab51c7678 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:03:15 -0700 Subject: [PATCH 068/345] Fix --make-repro-path option (#90989) Co-authored-by: Ivan Povazan Co-authored-by: Jan Kotas --- src/coreclr/tools/Common/CommandLineHelpers.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/tools/Common/CommandLineHelpers.cs b/src/coreclr/tools/Common/CommandLineHelpers.cs index 205592c1c91dca..3fb977a3047a6a 100644 --- a/src/coreclr/tools/Common/CommandLineHelpers.cs +++ b/src/coreclr/tools/Common/CommandLineHelpers.cs @@ -210,7 +210,7 @@ public static void MakeReproPackage(string makeReproPath, string outputFilePath, foreach (CliOption option in res.CommandResult.Command.Options) { OptionResult optionResult = res.GetResult(option); - if (optionResult is null || option.Name == "make-repro-path") + if (optionResult is null || option.Name == "--make-repro-path") { continue; } @@ -233,7 +233,7 @@ public static void MakeReproPackage(string makeReproPath, string outputFilePath, } foreach (string inputFile in dictionary.Values) { - rspFile.Add($"--{option.Name}:{ConvertFromOriginalPathToReproPackagePath(input: true, inputFile)}"); + rspFile.Add($"{option.Name}:{ConvertFromOriginalPathToReproPackagePath(input: true, inputFile)}"); } } else @@ -241,7 +241,7 @@ public static void MakeReproPackage(string makeReproPath, string outputFilePath, foreach (string optInList in values) { if (!string.IsNullOrEmpty(optInList)) - rspFile.Add($"--{option.Name}:{optInList}"); + rspFile.Add($"{option.Name}:{optInList}"); } } } @@ -254,11 +254,11 @@ public static void MakeReproPackage(string makeReproPath, string outputFilePath, // if output option is used, overwrite the path to the repro package stringVal = ConvertFromOriginalPathToReproPackagePath(input: false, stringVal); } - rspFile.Add($"--{option.Name}:{stringVal}"); + rspFile.Add($"{option.Name}:{stringVal}"); } else { - rspFile.Add($"--{option.Name}:{val}"); + rspFile.Add($"{option.Name}:{val}"); } } } From 09e32660cd775f57b375826178b9f6d2fa3338a7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:03:49 -0700 Subject: [PATCH 069/345] [release/8.0] [mono][interp] Mask all shift amounts (#90991) * [tests] Enable tests * [mono][interp] Mask all shift amounts --------- Co-authored-by: Vlad Brezae --- src/mono/mono/mini/interp/interp-simd.c | 18 +++++++++--------- .../VectorImmBinaryOperatorTest.template | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mono/mono/mini/interp/interp-simd.c b/src/mono/mono/mini/interp/interp-simd.c index 5031c87aaf206b..f21fdec5aefd3b 100644 --- a/src/mono/mono/mini/interp/interp-simd.c +++ b/src/mono/mono/mini/interp/interp-simd.c @@ -215,57 +215,57 @@ interp_v128_i2_op_left_shift (gpointer res, gpointer v1, gpointer s1) static void interp_v128_i4_op_left_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_i4*)res = *(v128_i4*)v1 << *(gint32*)s1; + *(v128_i4*)res = *(v128_i4*)v1 << (*(gint32*)s1 & 31); } static void interp_v128_i8_op_left_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_i8*)res = *(v128_i8*)v1 << *(gint32*)s1; + *(v128_i8*)res = *(v128_i8*)v1 << (*(gint32*)s1 & 63); } // op_RightShift static void interp_v128_i1_op_right_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_i1*)res = *(v128_i1*)v1 >> *(gint32*)s1; + *(v128_i1*)res = *(v128_i1*)v1 >> (*(gint32*)s1 & 7); } static void interp_v128_i2_op_right_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_i2*)res = *(v128_i2*)v1 >> *(gint32*)s1; + *(v128_i2*)res = *(v128_i2*)v1 >> (*(gint32*)s1 & 15); } static void interp_v128_i4_op_right_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_i4*)res = *(v128_i4*)v1 >> *(gint32*)s1; + *(v128_i4*)res = *(v128_i4*)v1 >> (*(gint32*)s1 & 31); } // op_UnsignedRightShift static void interp_v128_i1_op_uright_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_u1*)res = *(v128_u1*)v1 >> *(gint32*)s1; + *(v128_u1*)res = *(v128_u1*)v1 >> (*(gint32*)s1 & 7); } static void interp_v128_i2_op_uright_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_u2*)res = *(v128_u2*)v1 >> *(gint32*)s1; + *(v128_u2*)res = *(v128_u2*)v1 >> (*(gint32*)s1 & 15); } static void interp_v128_i4_op_uright_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_u4*)res = *(v128_u4*)v1 >> *(gint32*)s1; + *(v128_u4*)res = *(v128_u4*)v1 >> (*(gint32*)s1 & 31); } static void interp_v128_i8_op_uright_shift (gpointer res, gpointer v1, gpointer s1) { - *(v128_u8*)res = *(v128_u8*)v1 >> *(gint32*)s1; + *(v128_u8*)res = *(v128_u8*)v1 >> (*(gint32*)s1 & 63); } // op_OnesComplement diff --git a/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorImmBinaryOperatorTest.template b/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorImmBinaryOperatorTest.template index ff62ffcfc91335..d9b2108472675b 100644 --- a/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorImmBinaryOperatorTest.template +++ b/src/tests/JIT/HardwareIntrinsics/General/Shared/VectorImmBinaryOperatorTest.template @@ -19,7 +19,6 @@ namespace JIT.HardwareIntrinsics.General public static partial class Program { [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/89938", TestRuntimes.Mono)] public static void {Method}{RetBaseType}{Imm}() { var test = new VectorImmBinaryOpTest__{Method}{RetBaseType}{Imm}(); From 3d1b2543593f0dc3fbbdc2b8cad9b1f8e7554af6 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 23 Aug 2023 16:05:56 -0700 Subject: [PATCH 070/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2251098 (#90996) * Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2250829 * Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2250829 --- .../gen/Resources/xlf/Strings.cs.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.de.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.es.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.fr.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.it.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.ja.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.ko.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.pl.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.pt-BR.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.ru.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.tr.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 60 +++++++++---------- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 60 +++++++++---------- .../gen/Common/Resources/xlf/Strings.cs.xlf | 6 +- .../gen/Common/Resources/xlf/Strings.de.xlf | 6 +- .../gen/Common/Resources/xlf/Strings.es.xlf | 6 +- .../gen/Common/Resources/xlf/Strings.fr.xlf | 4 +- .../gen/Common/Resources/xlf/Strings.it.xlf | 4 +- .../gen/Common/Resources/xlf/Strings.ja.xlf | 6 +- .../gen/Common/Resources/xlf/Strings.ko.xlf | 6 +- .../gen/Common/Resources/xlf/Strings.pl.xlf | 4 +- .../Common/Resources/xlf/Strings.pt-BR.xlf | 6 +- .../gen/Common/Resources/xlf/Strings.ru.xlf | 4 +- .../gen/Common/Resources/xlf/Strings.tr.xlf | 4 +- .../Common/Resources/xlf/Strings.zh-Hans.xlf | 6 +- .../Common/Resources/xlf/Strings.zh-Hant.xlf | 4 +- .../gen/Resources/xlf/Strings.cs.xlf | 2 +- .../gen/Resources/xlf/Strings.de.xlf | 2 +- .../gen/Resources/xlf/Strings.es.xlf | 2 +- .../gen/Resources/xlf/Strings.fr.xlf | 2 +- .../gen/Resources/xlf/Strings.it.xlf | 2 +- .../gen/Resources/xlf/Strings.ja.xlf | 2 +- .../gen/Resources/xlf/Strings.ko.xlf | 2 +- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 2 +- .../gen/Resources/xlf/Strings.ru.xlf | 2 +- .../gen/Resources/xlf/Strings.tr.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 2 +- 39 files changed, 436 insertions(+), 436 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf index 7054599d224576..cf1eaeedf07021 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + Typ {0} již implementuje metodu Validate. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Typ už obsahuje implementaci metody Validate. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] nelze použít pro statickou třídu {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + OptionsValidatorAttribute nelze použít pro statickou třídu. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + U polí nebo vlastností s otevřeným obecným typem {0} nelze použít [ValidateObjectMembers] nebo [ValidateEnumeratedItems]. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + U polí nebo vlastností s otevřenými obecnými typy nelze použít ValidateObjectMembersAttribute nebo ValidateEnumeratedItemsAttribute. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Atributy ověřování nelze použít u konstantního ani statického člena {0}. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Nelze ověřit konstanty, statická pole ani vlastnosti. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Existuje cyklický odkaz obsahující typ {0}, který brání jeho použití pro statické ověření. Unsupported circular references in model types. - Unsupported circular references in model types. + Nepodporované cyklické odkazy v typech modelů. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + Typ {0} neimplementuje požadované rozhraní IValidateOptions<{1}> . A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Typ anotovaný třídou OptionsValidatorAttribute neimplementuje nezbytné rozhraní. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + Ověřovací atribut „{0}“ u člena „{1}“ není přístupný z typu validátoru „{2}“. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + Ověřovací atribut u člena není přístupný z typu validátoru. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Ověřovací atributy nelze použít u privátního pole nebo vlastnosti {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + Nelze ověřit privátní pole nebo vlastnosti. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + Typ {0} nemá žádná pole ani vlastnosti k ověření, na které odkazuje člen {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Typ člena nemá žádná pole ani vlastnosti k ověření. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + Typ {0} nemá žádná pole ani vlastnosti k ověření, na které odkazuje typ {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Typ nemá žádná pole ani vlastnosti k ověření. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] nelze použít u členů typu {0}, protože neimplementuje rozhraní IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + Typ členu není výčtový. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Typ validátoru s hodnotou null zadaný v atributech [ValidateObjectMembers] nebo [ValidateEnumeratedItems]. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Pro atributy ValidateObjectMembersAttribute nebo ValidateEnumeratedItemsAttribute byl specifikovaný typ validátoru s hodnotou null. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + Typ {0} obsahuje validační anotace, ale člen {1} neurčuje [ValidateEnumeratedItems], což může být přehlédnutí. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + U člena potenciálně chybí ověření výčtu. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + Typ {0} obsahuje validační anotace, ale člen {1} neurčuje [ValidateObjectMembers], což může být přehlédnutí. Member potentially missing transitive validation. - Member potentially missing transitive validation. + U člena potenciálně chybí přenositelné ověření. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + Typ validátoru {0} nemá konstruktor bez parametrů. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Validátory používané pro přenositelné nebo výčtové ověřování musí mít konstruktor bez parametrů. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf index 5f6febba85c205..507e5896457a51 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + Der Typ "{0}" implementiert bereits die Validate-Methode. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Ein Typ enthält bereits eine Implementierung der Validate-Methode. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] kann nicht auf die statische Klasse "{0}" angewendet werden. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + "OptionsValidatorAttribute" kann nicht auf eine statische Klasse angewendet werden. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + "ValidateObjectMembers" oder "ValidateEnumeratedItems" kann nicht für Felder oder Eigenschaften mit offenem generischen Typ {0} verwendet werden. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + "ValidateObjectMembersAttribute" oder "ValidateEnumeratedItemsAttribute" kann nicht für Felder oder Eigenschaften mit offenen generischen Typen verwendet werden. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Validierungsattribute können nicht auf konstanten oder statischen Member {0} angewendet werden. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Konstanten, statische Felder oder Eigenschaften können nicht überprüft werden. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Es gibt einen Zirkelverweis, der den Typ "{0}" verhindert, dass er für die statische Validierung verwendet wird. Unsupported circular references in model types. - Unsupported circular references in model types. + Nicht unterstützte Zirkelverweise in Modelltypen. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + Der Typ "{0}" implementiert nicht die erforderliche IValidateOptions<{1}>-Schnittstelle. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Ein mit "OptionsValidatorAttribute" versehener Typ implementiert nicht die erforderliche Schnittstelle. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + Auf das Validierungsattribut "{0}" für den Member "{1}" kann vom Validierungssteuerelementtyp "{2}" nicht zugegriffen werden. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + Auf das Validierungsattribut für den Member kann vom Validierungssteuerelementtyp nicht zugegriffen werden. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Validierungsattribute können nicht auf private Felder oder Eigenschaften {0} angewendet werden. Can't validate private fields or properties. - Can't validate private fields or properties. + Private Felder oder Eigenschaften können nicht überprüft werden. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + Der Typ "{0}" weist keine zu überprüfenden Felder oder Eigenschaften auf, auf die von Member "{1}" verwiesen wird. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Ein Membertyp weist keine zu überprüfenden Felder oder Eigenschaften auf. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + Der Typ "{0}" weist keine zu überprüfenden Felder oder Eigenschaften auf, auf die vom Typ "{1}" verwiesen wird. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Ein Typ weist keine zu überprüfenden Felder oder Eigenschaften auf. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] kann nicht für Member vom Typ "{0}" verwendet werden, da es IEnumerable<T> nicht implementiert. Member type is not enumerable. - Member type is not enumerable. + Der Membertyp ist nicht aufzählbar. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Der in den Attributen [ValidateObjectMembers] oder [ValidateEnumeratedItems] angegebene NULL-Validierungssteuerelementtyp. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Für die Attribute "ValidateObjectMembersAttribute" oder "ValidateEnumeratedItemsAttribute" wurde ein NULL-Validierungssteuerelementtyp angegeben. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + Der Typ "{0}" weist Validierungsanmerkungen auf, der Member "{1}" gibt jedoch keine [ValidateEnumeratedItems] an, die eine Vorhersage darstellen könnten. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Dem Mitglied fehlt möglicherweise eine aufzählbare Validierung. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + Der Typ "{0}" weist Validierungsanmerkungen auf, aber Member "{1}" gibt [ValidateObjectMembers] nicht an, was ein Versehen sein könnte. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Dem Member fehlt möglicherweise die transitive Validierung. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + Der Validierungssteuerelementtyp "{0}" hat keinen parameterlosen Konstruktor. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Validierungssteuerelemente, die für die transitive oder enumerierbare Validierung verwendet werden, müssen über einen Konstruktor ohne Parameter verfügen. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf index 84c12b9739ab1a..4ee57aa7312aa0 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + El tipo {0} ya implementa el método Validate. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Un tipo ya incluye una implementación del método “Validate”. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + No se puede aplicar [OptionsValidator] a la clase estática {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + “OptionsValidatorAttribute” no se puede aplicar a una clase estática. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + No se puede usar [ValidateObjectMembers] ni [ValidateEnumeratedItems] en campos o propiedades con tipos genéricos abiertos {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + No se puede usar “ValidateObjectMembersAttribute” o “ValidateEnumeratedItemsAttribute” en campos o propiedades con tipos genéricos abiertos. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + No se pueden aplicar atributos de validación a un miembro {0}constante o estático. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + No se pueden validar constantes, campos estáticos ni propiedades. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Hay una referencia de tipo circular que implica al tipo {0} que impide que se use para la validación estática. Unsupported circular references in model types. - Unsupported circular references in model types. + Referencias circulares no admitidas en los tipos de modelo. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + El tipo {0} no implementa la interfaz IValidateOptions<{1}> necesaria. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Un tipo anotado con “OptionsValidatorAttribute” no implementa la interfaz necesaria. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + No se puede obtener acceso al atributo de validación '{0}' en el miembro '{1}' desde el tipo de validador '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + No se puede obtener acceso al atributo de validación en el miembro desde el tipo de validador. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + No se pueden aplicar atributos de validación a la propiedad o campo privado {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + No se pueden validar los campos o propiedades privadas. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + El tipo {0} no tiene campos ni propiedades para validar, al que hace referencia el tipo {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Un tipo de miembro no tiene campos ni propiedades para validar. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + El tipo {0} no tiene campos ni propiedades para validar, al que hace referencia el tipo {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Un tipo no tiene campos ni propiedades para validar. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] no se puede usar en miembros de tipo {0} porque no implementa IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + El tipo de miembro no es enumerable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Se especificó un tipo de validador nulo en los atributos [ValidateObjectMembers] o [ValidateEnumeratedItems]. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Se especificó un tipo de validador nulo para los atributos “ValidateObjectMembersAttribute” o “ValidateEnumeratedItemsAttribute”. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + El tipo {0} tiene anotaciones de validación, pero el miembro {1} no especifica [ValidateEnumeratedItems], lo que podría ser un error. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Posiblemente falta la validación enumerable en el miembro. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + El tipo {0} tiene anotaciones de validación, pero el miembro {1} no especifica [ValidateObjectMembers], lo que podría ser un error. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Posiblemente falta la validación transitiva en el miembro. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + El tipo de validador {0} no tiene un constructor sin parámetros. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Los validadores usados para la validación transitiva o enumerable deben tener un constructor sin parámetros. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf index 58a27f1e4b33cb..9e300eaed00812 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + Le type {0} implémente déjà la méthode Validate. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Un type inclut déjà une implémentation de la méthode 'Validate'. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] ne peut pas être appliqué à la classe statique {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + 'OptionsValidatorAttribute' ne peut pas être appliqué à une classe statique. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + Impossible d’utiliser [ValidateObjectMembers] ou [ValidateEnumeratedItems] sur des champs ou des propriétés avec un type générique ouvert {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + Impossible d’utiliser 'ValidateObjectMembersAttribute' ou 'ValidateEnumeratedItemsAttribute' sur des champs ou des propriétés avec des types génériques ouverts. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Impossible d’appliquer les attributs de validation au membre constant ou statique {0}. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Impossible de valider les constantes, les champs statiques ou les propriétés. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Une référence de type circulaire implique un type {0} l’empêche d’être utilisé pour la validation statique. Unsupported circular references in model types. - Unsupported circular references in model types. + Références circulaires non prises en charge dans les types de modèle. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + Le type {0} n’implémente pas l’interface<{1}> IValidateOptions requise. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Un type annoté avec 'OptionsValidatorAttribute' n’implémente pas l’interface nécessaire. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + L’attribut de validation '{0}' sur le membre '{1}' n’est pas accessible à partir du type de validateur '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + L’attribut de validation sur le membre n’est pas accessible à partir du type de validateur. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Impossible d’appliquer les attributs de validation au champ privé ou à la propriété {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + Impossible de valider les champs ou propriétés privés. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + Le type {0} n’a aucun champ ou propriété à valider, référencé à partir du membre {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Un type de membre n’a aucun champ ou propriété à valider. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + Le type {0} n’a pas de champs ou de propriétés à valider, référencé par type {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Un type n’a pas de champs ou de propriétés à valider. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] ne peut pas être utilisé sur des membres de type {0}, car il n’implémente pas IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + Le type de membre n’est pas énumérable. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Type de validateur Null spécifié dans les attributs [ValidateObjectMembers] ou [ValidateEnumeratedItems]. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Type de validateur Null spécifié pour les attributs 'ValidateObjectMembersAttribute' ou 'ValidateEnumeratedItemsAttribute'. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + Le type {0} a des annotations de validation, mais le membre {1} ne spécifie pas [ValidateEnumeratedItems] qui peut être une supervision. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Le membre n’a peut-être pas de validation énumérable. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + Le type {0} a des annotations de validation, mais le membre {1} ne spécifie pas [ValidateObjectMembers] qui pourrait être une méthode de récupération. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Le membre n’a peut-être pas de validation transitive. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + Le type de validateur {0} n’a pas de constructeur sans paramètre. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Les validateurs utilisés pour la validation transitive ou énumérable doivent avoir un constructeur sans paramètres. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf index 2355a93c01db99..f59cc9dcbeeefb 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + Il tipo {0} implementa già il metodo Validate. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Un tipo include già un'implementazione del metodo 'Validate'. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + impossibile applicare [OptionsValidator] alla classe statica {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + 'OptionsValidatorAttribute' non può essere applicato a una classe statica. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + Non è possibile usare [ValidateObjectMembers] o [ValidateEnumeratedItems] in campi o proprietà con tipo generico aperto {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + Non è possibile usare 'ValidateObjectMembersAttribute' o 'ValidateEnumeratedItemsAttribute' nei campi o nelle proprietà con tipi generici aperti. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Non è possibile applicare attributi di convalida a un membro costante o statico {0}. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Non è possibile convalidare costanti, campi statici o proprietà. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Esiste un riferimento di tipo circolare che interessa il tipo {0} e ne impedisce l'utilizzo per la convalida statica. Unsupported circular references in model types. - Unsupported circular references in model types. + Riferimenti circolari non supportati nei tipi di modello. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + Il tipo {0} non implementa l'interfaccia IValidateOptions<{1}> richiesta. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Un tipo annotato con 'OptionsValidatorAttribute' non implementa l'interfaccia necessaria. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + L'attributo di convalida '{0}' nel membro '{1}' non è accessibile dal tipo di validator '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + L'attributo di convalida nel membro non è accessibile dal tipo di validator. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Non è possibile applicare gli attributi di convalida al campo privato o alla proprietà {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + Non è possibile convalidare proprietà o campi privati. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + Il tipo {0} non contiene campi o proprietà da convalidare, riferiti dal membro {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Un tipo di membro non contiene campi o proprietà da convalidare. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + Il tipo {0} non contiene campi o proprietà da convalidare, riferiti per tipo {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Un tipo non contiene campi o proprietà da convalidare. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] non può essere usato nei membri di tipo {0} perché non implementa IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + Il tipo di membro non è enumerabile. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Tipo di validator Null specificato negli attributi [ValidateObjectMembers] o [ValidateEnumeratedItems]. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Tipo di validator Null specificato per gli attributi 'ValidateObjectMembersAttribute' o 'ValidateEnumeratedItemsAttribute'. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + Il tipo {0} include annotazioni di convalida, ma il membro {1} non specifica [ValidateEnumeratedItems] che potrebbe essere una supervisione. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Convalida enumerabile potenzialmente mancante nel membro. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + Il tipo {0} include annotazioni di convalida, ma il membro {1} non specifica [ValidateObjectMembers] che potrebbe essere una supervisione. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Il membro potrebbe non avere una convalida transitiva. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + Il tipo di convalida {0} non dispone di un costruttore senza parametri. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + I convalidatori usati per la convalida transitiva o enumerabile devono avere un costruttore senza parametri. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf index 60e9a7db80c8d4..72a828f97c5e29 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + 型 {0} に Validate メソッドが既に実装されています。 A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + 型には 'Validate' メソッドの実装が既に含まれています。 [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + 静的クラス {0} には [OptionsValidator] を適用できません。 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + 'OptionsValidatorAttribute' は静的クラスに適用できません。 Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + [ValidateObjectMembers] または [ValidateEnumeratedItems] は、オープンジェネリック型 {0} を持つフィールドまたはプロパティでは使用できません。 Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + 'ValidateObjectMembersAttribute' または 'ValidateEnumeratedItemsAttribute' は、オープンジェネリック型を持つフィールドまたはプロパティでは使用できません。 Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + 定数または静的メンバー {0} に検証属性を適用できません。 Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + 定数、静的フィールド、またはプロパティを検証できません。 There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + 型{0}を含む循環型参照があるため、静的検証に使用できません。 Unsupported circular references in model types. - Unsupported circular references in model types. + モデル型でサポートされていない循環参照です。 Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + 必要な IValidateOptions<{1}> インターフェイスが型 {0} に実装されていません。 A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + 'OptionsValidatorAttribute' の注釈が付けられた型が、必要とされるインターフェイスを実装していません。 Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + メンバー '{0}' の検証属性 '{1}' は、検証コントロールの種類 '{2}'からアクセスできません。 Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + メンバーの検証属性は、検証コントロールの種類からアクセスできません... Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + プライベート フィールドまたはプロパティ {0} には検証属性を適用できません。 Can't validate private fields or properties. - Can't validate private fields or properties. + プライベート フィールドまたはプロパティを検証できません。 Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + 型 {0} にメンバー {1} から参照されている検証対象のフィールドまたはプロパティがありません。 A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + メンバー型に検証対象のフィールドまたはプロパティがありません。 Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + 型 {0} に型 {1} で参照されている検証対象のフィールドまたはプロパティがありません。 A type has no fields or properties to validate. - A type has no fields or properties to validate. + 型に検証対象のフィールドまたはプロパティがありません。 [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] は IEnumerable<T> を実装していないため、型 {0} のメンバーでは使用できません。 Member type is not enumerable. - Member type is not enumerable. + メンバー型は列挙型ではありません。 Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + [ValidateObjectMembers] 属性または [ValidateEnumeratedItems] 属性で null のバリデーター型が指定されています。 Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + 'ValidateObjectMembersAttribute' 属性または 'ValidateEnumeratedItemsAttribute' 属性に対して NULL のバリデーター型が指定されています。 @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + 型 {0} には検証の注釈がありますが、メンバー {1} では [ValidateEnumeratedItem] が指定されていません。これは誤りである可能性があります。 Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + 列挙型の検証がメンバーに存在しない可能性があります。 Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + 型 {0} には検証の注釈がありますが、メンバー {1} では [ValidateObjectMembers] が指定されていません。これは誤りである可能性があります。 Member potentially missing transitive validation. - Member potentially missing transitive validation. + メンバーに推移性の検証がない可能性があります。 Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + バリデーター型 {0} にパラメーターなしのコンストラクターがありません。 Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + 推移性または列挙型の検証に使用されるバリデーターには、パラメーターのないコンストラクターが必要です。 diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf index e350b2f6f437de..9018aaf6993610 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + 형식 {0}은(는) Validate 메서드를 이미 구현하고 있습니다. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + 형식에 'Validate' 메서드 구현이 이미 포함되어 있습니다. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator]은(는) 정적 클래스 {0}에 적용할 수 없습니다. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + 'OptionsValidatorAttribute'는 정적 클래스에 적용할 수 없습니다. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + 열린 제네릭 형식 {0}의 필드 또는 속성에는 [ValidateObjectMembers] 또는 [ValidateEnumeratedItems]을(를) 사용할 수 없습니다. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + 열린 제네릭 형식의 필드 또는 속성에는 'ValidateObjectMembersAttribute' 또는 'ValidateEnumeratedItemsAttribute'를 사용할 수 없습니다. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + 상수 또는 정적 멤버 {0}에 유효성 검사 특성을 적용할 수 없습니다. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + 상수, 정적 필드 또는 속성을 확인할 수 없습니다. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + 정적 유효성 검사에 사용할 수 없으므로 형식 {0} 관련된 순환 형식 참조가 있습니다. Unsupported circular references in model types. - Unsupported circular references in model types. + 모델 형식에 지원되지 않는 순환 참조가 있습니다. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + 형식 {0}은(는) 필요한 IValidateOptions<{1}> 인터페이스를 구현하지 않습니다. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + 'OptionsValidatorAttribute'로 주석이 추가된 형식은 필요한 인터페이스를 구현하지 않습니다. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + 유효성 검사기 유형 '{2}'에서 '{1}' 멤버의 '{0}' 유효성 검사 특성에 액세스할 수 없습니다. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + 유효성 검사기 유형에서 멤버의 유효성 검사 특성에 액세스할 수 없습니다. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + 프라이빗 필드 또는 속성 {0}에 유효성 검사 특성을 적용할 수 없습니다. Can't validate private fields or properties. - Can't validate private fields or properties. + 프라이빗 필드 또는 속성의 유효성을 검사할 수 없습니다. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + 형식 {0}은(는) 유효성을 검사할 필드 또는 속성이 없으므로 멤버 {1}을(를) 참조합니다. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + 멤버 형식에 유효성을 검사할 필드 또는 속성이 없습니다. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + 형식 {0}은(는) 유효성을 검사할 필드 또는 속성이 없으므로 형식 {1}을(를) 참조합니다. A type has no fields or properties to validate. - A type has no fields or properties to validate. + 형식에 유효성을 검사할 필드 또는 속성이 없습니다. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems]은(는) IEnumerable<T>을(를) 구현하지 않으므로 형식 {0}의 멤버에 사용할 수 없습니다. Member type is not enumerable. - Member type is not enumerable. + 멤버 형식을 열거할 수 없습니다. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + [ValidateObjectMembers] 또는 [ValidateEnumeratedItems] 특성에 Null 유효성 검사기 형식이 지정되었습니다. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + 'ValidateObjectMembersAttribute' 또는 'ValidateEnumeratedItemsAttribute' 특성에 Null 유효성 검사기 형식이 지정되었습니다. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + 형식 {0}은(는) 유효성 검사 주석이 있지만 멤버 {1}은(는) 참조할 수 있는 [ValidateEnumeratedItems]을(를) 지정하지 않습니다. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + 멤버에 열거 가능한 유효성 검사가 누락되었을 수 있습니다. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + 형식 {0}은(는) 유효성 검사 주석이 있지만 멤버 {1}은(는) 참조할 수 있는 [ValidateObjectMembers]을(를) 지정하지 않습니다. Member potentially missing transitive validation. - Member potentially missing transitive validation. + 멤버에 전이적 유효성 검사가 누락되었을 수 있습니다. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + 유효성 검사기 형식 {0}은(는) 매개 변수가 없는 생성자가 없습니다. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + 전이적 또는 열거형 유효성 검사에 사용되는 유효성 검사기에는 매개 변수가 없는 생성자가 있어야 합니다. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf index edaf8b9d00e9ba..126471f22a6c9e 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + Typ {0} już implementuje metodę Validate. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Typ zawiera już implementację metody „Validate”. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + Nie można zastosować elementu [OptionsValidator] do klasy statycznej {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + Nie można zastosować elementu „OptionsValidatorAttribute” do klasy statycznej. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + Nie można użyć atrybutu [ValidateObjectMembers] lub [ValidateEnumeratedItems] w polach lub właściwościach z otwartymi typami ogólnymi {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + Nie można użyć atrybutu „ValidateObjectMembersAttribute” lub „ValidateEnumeratedItemsAttribute” w polach lub właściwościach z otwartymi typami ogólnymi. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Nie można zastosować atrybutów walidacji do stałych lub statycznych elementów członkowskich {0}. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Nie można zweryfikować stałych, pól statycznych lub właściwości. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Istnieje cykliczne odwołanie do typu dotyczące typu {0} uniemożliwiające użycie go do weryfikacji statycznej. Unsupported circular references in model types. - Unsupported circular references in model types. + Nieobsługiwane odwołania cykliczne w typach modeli. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + Typ {0} nie implementuje wymaganego interfejsu IValidateOptions<{1}>. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Typ z adnotacją „OptionsValidatorAttribute” nie implementuje wymaganego interfejsu. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + Atrybut walidacji „{0}” elementu członkowskiego „{1}” jest niedostępny z typu modułu sprawdzania poprawności „{2}”. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + Atrybut walidacji elementu członkowskiego jest niedostępny z typu modułu sprawdzania poprawności. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Nie można zastosować atrybutów weryfikacji do pola prywatnego lub właściwości {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + Nie można zweryfikować prywatnych pól lub właściwości. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + Typ {0} nie ma pól ani właściwości do zweryfikowania, do których odwołuje się element członkowski {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Typ elementu członkowskiego nie ma pól ani właściwości do zweryfikowania. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + Typ {0} nie ma pól ani właściwości do zweryfikowania, do których odwołuje się typ {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Typ nie ma pól ani właściwości do zweryfikowania. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + Atrybutu [ValidateEnumeratedItems] nie można używać w przypadku elementów członkowskich typu {0}, ponieważ nie implementuje interfejsu IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + Nie można wyliczyć typu elementu członkowskiego. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + W atrybutach [ValidateObjectMembers] lub [ValidateEnumeratedItems] określono typ modułu sprawdzania poprawności o wartości null. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Określono typ modułu sprawdzania poprawności o wartości null dla atrybutu „ValidateObjectMembersAttribute” lub „ValidateEnumeratedItemsAttribute”. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + Typ {0} ma adnotacje walidacji, ale element członkowski {1} nie określa atrybutu [ValidateEnumeratedItems], co może być przeoczeniem. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + W elemencie członkowskim może brakować walidacji możliwej do wyliczenia. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + Typ {0} ma adnotacje walidacji, ale element członkowski {1} nie określa atrybutu [ValidateObjectMembers], co może być przeoczeniem. Member potentially missing transitive validation. - Member potentially missing transitive validation. + W przypadku elementu członkowskiego może potencjalnie brakować weryfikacji przechodniej. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + Typ modułu sprawdzania poprawności {0} nie ma konstruktora bez parametrów. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Moduły sprawdzania poprawności używane do weryfikacji przechodniej lub weryfikacji możliwej do wyliczenia muszą mieć konstruktora bez żadnych parametrów. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf index f62a1ef241e372..dcc8db9dcbefe4 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + O tipo {0} já implementa o método Validar. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Um tipo já inclui uma implementação do método "Validar". [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] não pode ser aplicado à classe estática {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + "OptionsValidatorAttribute" não pode ser aplicado a uma classe estática. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + Não é possível usar [ValidateObjectMembers] ou [ValidateEnumeratedItems] em campos ou propriedades com o tipo genérico aberto {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + Não é possível usar "ValidateObjectMembersAttribute" ou "ValidateEnumeratedItemsAttribute" em campos ou propriedades com tipos genéricos abertos. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Não é possível aplicar atributos de validação a um membro constante ou estático {0}. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Não é possível validar constantes, campos estáticos ou propriedades. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Há uma referência de tipo circular que envolve o tipo {0} que a impede de ser usada para validação estática. Unsupported circular references in model types. - Unsupported circular references in model types. + Referências circulares sem suporte em tipos de modelo. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + O tipo {0} não implementa a interface IValidateOptions<{1}> necessária. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Um tipo anotado com "OptionsValidatorAttribute" não implementa a interface necessária. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + O atributo de validação '{0}' no membro '{1}' está inacessível do tipo de validador '{2}'. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + O atributo de validação no membro está inacessível do tipo de validador. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Não é possível aplicar atributos de validação a um campo privado ou propriedade {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + Não é possível validar propriedades ou campos privados. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + O tipo {0} não tem campos ou propriedades para validar, referenciados do membro {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Um tipo de membro não tem campos ou propriedades a serem validados. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + O tipo {0} não tem campos ou propriedades para validar, referenciados por tipo {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Um tipo não tem campos ou propriedades a serem validados. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] não pode ser usado em membros do tipo {0}, pois ele não implementa IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + O tipo de membro não é enumerável. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Tipo de validador nulo especificado nos atributos [ValidateObjectMembers] ou [ValidateEnumeratedItems]. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Tipo de validador nulo especificado para os atributos "ValidateObjectMembersAttribute" ou "ValidateEnumeratedItemsAttribute". @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + O tipo {0} tem anotações de validação, mas o membro {1} não especifica [ValidateEnumeratedItems], o que pode ser uma desatenção. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Membro potencialmente ausente na validação enumerável. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + O tipo {0} tem anotações de validação, mas o membro {1} não especifica [ValidateObjectMembers], o que pode ser uma desatenção. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Membro potencialmente ausente na validação transitiva. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + O tipo de validador {0} não tem um construtor sem parâmetros. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Os validadores usados para validação transitiva ou enumerável devem ter um construtor sem parâmetros. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf index b8069e4266ae37..c1fd957bf6c53d 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + Тип {0} уже реализует метод Validate. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Тип уже содержит реализацию метода Validate. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] невозможно применить к статическому классу {0}. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + Параметр OptionsValidatorAttribute не может быть применен к статическому классу. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + Нельзя использовать [ValidateObjectMembers] или [ValidateEnumeratedItems] для полей или свойств с открытыми универсальными типами {0}. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + Нельзя использовать "ValidateObjectMembersAttribute" или "ValidateEnumeratedItemsAttribute" для полей или свойств с открытыми универсальными типами. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Не удалось применить атрибуты проверки к константе или статическому элементу {0}. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Не удалось проверить константы, статические поля или свойства. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Существует циклическая ссылка на тип, включающая тип {0}, предотвращающий его использование для статической проверки. Unsupported circular references in model types. - Unsupported circular references in model types. + Неподдерживаемые циклические ссылки в типах моделей. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + Тип {0} не реализует требуемый интерфейс IValidateOptions<{1}>. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + Тип с аннотацией OptionsValidatorAttribute не реализует необходимый интерфейс. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + Атрибут проверки "{0}" элемента "{1}" недоступен из типа средства проверки "{2}". Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + Атрибут проверки элемента недоступен из типа средства проверки. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Не удается применить атрибуты проверки к закрытому полю или свойству {0}. Can't validate private fields or properties. - Can't validate private fields or properties. + Не удается проверить частные поля или свойства. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + Тип {0} не содержит полей или свойств для проверки, на которые ссылается из элемента {1}. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Тип элемента не имеет полей или свойств для проверки. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + Тип {0} не содержит полей или свойств для проверки, на которые ссылается тип {1}. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Тип не имеет полей или свойств для проверки. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] не может использоваться для элементов типа {0}, так как он не реализует IEnumerable<T>. Member type is not enumerable. - Member type is not enumerable. + Тип элемента не является перечисляемым. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + Тип проверяющего элемента управления, указанный в [ValidateObjectMembers] или [ValidateEnumeratedItems] атрибутах, имеет значение NULL. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + Для атрибутов ValidateObjectMembersAttribute или ValidateEnumeratedItemsAttribute указан тип проверяющего элемента управления NULL. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + Тип {0} содержит примечания проверки, но элемент {1} не указывает [ValidateEnumeratedItems], который может быть задан. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Элемент потенциально пропускает перечисляемую проверку. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + Тип {0} содержит примечания проверки, но элемент {1} не указывает [ValidateObjectMembers], который может быть задан. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Возможно, в элементе отсутствует транзитивная проверка. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + Тип проверяющего элемента управления {0} не имеет конструктора без параметров. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + У проверяющих элементов управления, используемых для транзитивной или перечисляемой проверки, должен быть конструктор без параметров. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf index 8cb34b9b6f900a..4adda20ccd1581 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + {0} türü Doğrulama yöntemini zaten uyguluyor. A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + Bir tür zaten 'Validate' yönteminin bir uygulamasını içeriyor. [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator], {0} statik sınıfına uygulanamıyor. 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + 'OptionsValidatorAttribute' statik sınıfa uygulanamaz. Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + {0} açık genel türündeki alanlarda veya özelliklerde [ValidateObjectMembers] veya [ValidateEnumeratedItems] kullanılamaz. Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + Açık genel türleri olan alanlarda veya özelliklerde 'ValidateObjectMembersAttribute' veya 'ValidateEnumeratedItemsAttribute' kullanılamaz. Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + Doğrulama öznitelikleri sabit veya statik üye {0} için geçerli değildir. Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + Sabitler, statik alanlar veya özellikler doğrulanamıyor. There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + Statik doğrulama için kullanılmasını engelleyen {0} türü içeren döngüsel bir tür başvurusu var. Unsupported circular references in model types. - Unsupported circular references in model types. + Model türlerde döngüsel başvurular desteklenmiyor. Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + {0} türü gerekli IValidateOptions<{1}> arabirimini uygulamıyor. A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + 'OptionsValidatorAttribute' ile açıklama eklenmiş bir tür gerekli arabirimi uygulamıyor. Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + '{1}' adlı üye üzerindeki '{0}' doğrulama özniteliğine '{2}' doğrulayıcı türünden erişilemiyor. Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + Üye üzerindeki doğrulama özniteliğine doğrulayıcı türünden erişilemiyor. Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + Doğrulama öznitelikleri, {0} özel alanına veya özelliğine uygulanamıyor. Can't validate private fields or properties. - Can't validate private fields or properties. + Özel alanlar veya özellikler doğrulanamıyor. Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + {0} türünde doğrulanacak alan veya özellik yok, {1} üyesinden başvurulur. A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + Üye türünde doğrulanacak alan veya özellik yok. Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + {0} türünde doğrulanacak alan veya özellik yok, {1} türü tarafından başvurulur. A type has no fields or properties to validate. - A type has no fields or properties to validate. + Türde doğrulanacak alan veya özellik yok. [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems], IEnumerable<T> uygulamadığından {0} türündeki üyeler üzerinde kullanılamıyor. Member type is not enumerable. - Member type is not enumerable. + Üye türü numaralandırılabilir değil. Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + [ValidateObjectMembers] veya [ValidateEnumeratedItems] özniteliklerinde null doğrulayıcı türü belirtildi. Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + 'ValidateObjectMembersAttribute' veya 'ValidateEnumeratedItemsAttribute' öznitelikleri için null doğrulayıcı türü belirtildi. @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + {0} türünde doğrulama ek açıklamaları var, ancak {1} üyesi gözden kaçmış olabilecek [ValidateEnumeratedItems] belirtmiyor. Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + Üyede numaralandırılabilir doğrulama eksik olabilir. Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + {0} türünde doğrulama ek açıklamaları var, ancak {1} üyesi gözden kaçmış olabilecek [ValidateObjectMembers] belirtmiyor. Member potentially missing transitive validation. - Member potentially missing transitive validation. + Üyede geçişli doğrulama eksik olabilir. Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + {0} doğrulayıcı türü parametresiz bir oluşturucuya sahip değil. Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + Geçişli veya numaralandırılabilir doğrulama için kullanılan doğrulayıcıların parametresi olmayan bir oluşturucusu olmalıdır. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf index 707dcb36c697b0..4a6d79badc79f4 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + 类型 {0} 已实现 Validate 方法。 A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + 类型已包含“Validate”方法的实现。 [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] 无法应用于静态类 {0}。 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + “OptionsValidatorAttribute”不能应用于静态类。 Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + 不能对具有开放泛型类型 {0} 的字段或属性使用 [ValidateObjectMembers] 或 [ValidateEnumeratedItems]。 Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + 不能对具有开放泛型类型的字段或属性使用 "ValidateObjectMembersAttribute" 或 "ValidateEnumeratedItemsAttribute"。 Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + 无法将验证属性应用于常量或静态成员 {0}。 Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + 无法验证常量、静态字段或属性。 There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + 存在一个循环类型引用,其中涉及的类型 {0} 阻止将其用于静态验证。 Unsupported circular references in model types. - Unsupported circular references in model types. + 模型类型中不支持的循环引用。 Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + 类型 {0} 未实现所需的 IValidateOptions<{1}> 接口。 A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + 用 "OptionsValidatorAttribute" 批注的类型未实现必要的接口。 Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + 无法从验证程序类型“{2}”访问成员“{1}”上的验证属性“{0}”。 Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + 无法从验证程序类型访问成员上的验证属性。 Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + 无法将验证属性应用于专用字段或属性 {0}。 Can't validate private fields or properties. - Can't validate private fields or properties. + 无法验证专用字段或属性。 Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + 类型 {0} 没有要验证的字段或属性,从成员 {1} 中引用。 A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + 成员类型没有要验证的字段或属性。 Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + 类型 {0} 没有要验证的字段或属性,由类型 {1} 引用。 A type has no fields or properties to validate. - A type has no fields or properties to validate. + 类型没有要验证的字段或属性。 [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + 无法对类型 {0} 的成员使用 [ValidateEnumeratedItems],因为它未实现 IEnumerable<T>。 Member type is not enumerable. - Member type is not enumerable. + 成员类型不可枚举。 Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + [ValidateObjectMembers] 或 [ValidateEnumeratedItems] 属性中指定的 Null 验证程序类型。 Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + 为“ValidateObjectMembersAttribute”或“ValidateEnumeratedItemsAttribute”属性指定的验证程序类型为 Null。 @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + 类型 {0} 具有验证注释,但成员 {1} 未指定 [ValidateEnumeratedItems],这可能是一种监督。 Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + 成员可能缺少可枚举验证。 Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + 类型 {0} 具有验证注释,但成员 {1} 未指定 [ValidateObjectMembers],这可能是一种监督。 Member potentially missing transitive validation. - Member potentially missing transitive validation. + 成员可能缺少可传递验证。 Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + 验证程序类型 {0} 没有无参数构造函数。 Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + 用于可传递验证或可枚举验证的验证程序必须具有没有参数的构造函数。 diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf index f8087186cb294b..f0d9a24cdfb1eb 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -4,122 +4,122 @@ Type {0} already implements the Validate method. - Type {0} already implements the Validate method. + 類型 {0} 已實作 [驗證] 方法。 A type already includes an implementation of the 'Validate' method. - A type already includes an implementation of the 'Validate' method. + 類型已經包含 [驗證] 方法的實作。 [OptionsValidator] cannot be applied to static class {0}. - [OptionsValidator] cannot be applied to static class {0}. + [OptionsValidator] 無法套用至靜態類別 {0}。 'OptionsValidatorAttribute' can't be applied to a static class. - 'OptionsValidatorAttribute' can't be applied to a static class. + 無法將 'OptionsValidatorAttribute' 套用至靜態類別。 Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. - Can't use [ValidateObjectMembers] or [ValidateEnumeratedItems] on fields or properties with open generic type {0}. + 無法在有開放式泛型型別 {0} 的欄位或屬性上使用 [ValidateObjectMembers] 或 [ValidateEnumeratedItems]。 Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. - Can't use 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' on fields or properties with open generic types. + 無法在有開放式泛型型別的欄位或屬性上使用 'ValidateObjectMembersAttribute' 或 'ValidateEnumeratedItemsAttribute'。 Can't apply validation attributes to constant or static member {0}. - Can't apply validation attributes to constant or static member {0}. + 無法將驗證屬性套用至常數或靜態成員 {0}。 Can't validate constants, static fields or properties. - Can't validate constants, static fields or properties. + 無法驗證常數、靜態欄位或屬性。 There is a circular type reference involving type {0} preventing it from being used for static validation. - There is a circular type reference involving type {0} preventing it from being used for static validation. + 有涉及類型 {0} 的循環類型參考讓它無法用於靜態驗證。 Unsupported circular references in model types. - Unsupported circular references in model types. + 模型類型中不支援的循環參考。 Type {0} does not implement the required IValidateOptions<{1}> interface. - Type {0} does not implement the required IValidateOptions<{1}> interface. + 類型 {0} 未實作必要的 IValidateOptions<{1}> 介面。 A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. - A type annotated with 'OptionsValidatorAttribute' doesn't implement the necessary interface. + 以 'OptionsValidatorAttribute' 附註的類型未實作必要的介面。 Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. - Validation attribute '{0}' on the member '{1}' is inaccessible from the validator type '{2}'. + 無法從驗證程式類型 '{2}' 存取成員 '{1}' 上的驗證屬性 '{0}'。 Validation attribute on the member is inaccessible from the validator type.. - Validation attribute on the member is inaccessible from the validator type.. + 無法從驗證程式類型存取成員上的驗證屬性。 Can't apply validation attributes to private field or property {0}. - Can't apply validation attributes to private field or property {0}. + 無法將驗證屬性套用至私用欄位或屬性 {0}。 Can't validate private fields or properties. - Can't validate private fields or properties. + 無法驗證私人欄位或屬性。 Type {0} has no fields or properties to validate, referenced from member {1}. - Type {0} has no fields or properties to validate, referenced from member {1}. + 參照會員 {1},類型 {0} 沒有欄位或屬性可供驗證。 A member type has no fields or properties to validate. - A member type has no fields or properties to validate. + 成員類型沒有欄位或屬性可供驗證。 Type {0} has no fields or properties to validate, referenced by type {1}. - Type {0} has no fields or properties to validate, referenced by type {1}. + 參照類型 {1},類型 {0} 沒有欄位或屬性可供驗證。 A type has no fields or properties to validate. - A type has no fields or properties to validate. + 類型沒有欄位或屬性可供驗證。 [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. - [ValidateEnumeratedItems] cannot be used on members of type {0} as it doesn't implement IEnumerable<T>. + [ValidateEnumeratedItems] 無法用於類型 {0} 的成員,因為其未實作 IEnumerable<T>。 Member type is not enumerable. - Member type is not enumerable. + 成員類型無法列舉。 Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. - Null validator type specified in [ValidateObjectMembers] or [ValidateEnumeratedItems] attributes. + [ValidateObjectMembers] 或 [ValidateEnumeratedItems] 屬性中指定的 Null 驗證程式類型。 Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. - Null validator type specified for the 'ValidateObjectMembersAttribute' or 'ValidateEnumeratedItemsAttribute' attributes. + 為 'ValidateObjectMembersAttribute' 或 'ValidateEnumeratedItemsAttribute' 屬性指定的 Null 驗證程式類型。 @@ -134,32 +134,32 @@ Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateEnumeratedItems] which could be an oversight. + 成員 {0} 具備驗證註釋,但成員 {1} 未指定 [ValidateObjectMembers] (可能為監督)。 Member potentially missing enumerable validation. - Member potentially missing enumerable validation. + 成員可能遺漏可列舉的驗證。 Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. - Type {0} has validation annotations, but member {1} doesn't specify [ValidateObjectMembers] which could be an oversight. + 類型 {0} 具備驗證註釋,但成員 {1} 未指定 [ValidateObjectMembers] (可能為監督)。 Member potentially missing transitive validation. - Member potentially missing transitive validation. + 成員可能遺漏轉移的驗證。 Validator type {0} doesn't have a parameterless constructor. - Validator type {0} doesn't have a parameterless constructor. + 驗證程式類型 {0} 沒有無參數建構函式。 Validators used for transitive or enumerable validation must have a constructor with no parameters. - Validators used for transitive or enumerable validation must have a constructor with no parameters. + 用於轉移或可列舉驗證的驗證程式必須具備沒有參數的建構函式。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf index aba6380486a3b7..e1b25c7690ffa4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + Typ {0} bude v nativním podpisu považován za strukturu, nikoli za nativní HRESULT. Pokud jej chcete považovat za HRESULT, přidejte do metody [return:MarshalAs(UnmanagedType.Error)]. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Tento typ bude v nativním podpisu považován za strukturu, nikoli za nativní HRESULT. @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Atribut „[Out]“ se podporuje pouze u parametrů pole. Zvažte použití klíčových slov „out“ nebo „ref“, aby se parametr dalo měnit. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf index 6b978f9aff5a9f..1b056b0cb4118e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + Der Typ '{0}' wird als Struktur in der nativen Signatur und nicht als natives HRESULT behandelt. Um ihn als HRESULT zu behandeln, fügen Sie der Methode "[return:MarshalAs(UnmanagedType.Error)]" hinzu. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Dieser Typ wird als Struktur in der nativen Signatur und nicht als natives HRESULT behandelt @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Das [Out]-Attribut wird nur für Arrayparameter gemarshallt werden. Erwägen Sie die Verwendung der Schlüsselwörter "out" oder "ref", um den Parameter änderbar zu machen. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf index 077827dbf7ef9b..7d67b06c68960e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + El tipo '{0}' se tratará como un struct en la firma nativa, no como un HRESULT nativo. Para tratarlo como un HRESULT, añade '[return:MarshalAs(UnmanagedType.Error)]' al método. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Este tipo se tratará como una estructura en la firma nativa, no como un HRESULT nativo. @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + El atributo "[Out]" solo se admite en parámetros de matriz. Considere la posibilidad de usar palabras clave "out" o "ref" para hacer que el parámetro sea mutable. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index 7b06fbb9966ce1..e4a153641da409 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + Le type « {0} » sera traité en tant que struct dans la signature native, et non en tant que HRESULT natif. Pour le traiter en tant que HRESULT, ajoutez « [return:MarshalAs(UnmanagedType.Error)] » à la méthode. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Ce type sera traité en tant que struct dans la signature native, et non en tant que HRESULT natif diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf index ee4ead36b3e114..acc74fc43e9ed5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + Il tipo '{0}' verrà considerato come uno struct nella firma nativa, non come HRESULT nativo. Per considerare questo valore come HRESULT, aggiungere '[return:MarshalAs(UnmanagedType.Error)]' al metodo. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Questo tipo verrà considerato come uno struct nella firma nativa, non come HRESULT nativo diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf index 9c12755cb80b44..946718bd8962ed 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + 型 '{0}' は、ネイティブ HRESULT としてではなく、ネイティブ シグネチャ内の構造体として扱われます。これを HRESULT として扱うには、'[return:MarshalAs(UnmanagedType.Error)]' をメソッドに追加します。 This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + この型はネイティブの HRESULT ではなく、ネイティブ シグネチャの構造体として扱われます @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + '[Out]' 属性は、配列パラメーターでのみサポートされます。パラメーターを変更可能にするには、'out' または 'ref' キーワードを使用することを検討してください。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index 53b72d47f60fa3..baa3e6381b26d7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + '{0}' 형식은 네이티브 HRESULT가 아니라 네이티브 서명에서 구조체로 처리됩니다. HRESULT로 처리하려면 메서드에 '[return:MarshalAs(UnmanagedType.Error)]'를 추가하세요. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + 이 형식은 네이티브 HRESULT가 아니라 네이티브 서명의 구조체로 처리됩니다. @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + '[Out]' 특성은 배열 매개 변수에서만 지원됩니다. 매개 변수를 변경할 수 있도록 'out' 또는 'ref' 키워드를 사용하는 것이 좋습니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index fb6cf9f172c21b..5f5447d2cd1ec5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + Typ „{0}” będzie traktowany jako struktura w podpisie natywnym, a nie jako natywny wynik HRESULT. Aby traktować to jako HRESULT, dodaj element „[return:MarshalAs(UnmanagedType.Error)]” do metody. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Ten typ będzie traktowany jako struktura w podpisie natywnym, a nie jako natywny wynik HRESULT diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index 8d2e606d2d0307..5eac2e488d6ee1 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + O tipo '{0}' será tratado como uma estrutura na assinatura nativa, não como um HRESULT nativo. Para tratar isso como um HRESULT, adicione '[return:MarshalAs(UnmanagedType.Error)]' ao método. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Este tipo será tratado como uma estrutura na assinatura nativa, não como um HRESULT nativo @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + O atributo "[Out]" só tem suporte em parâmetros de matriz. Considere usar palavras-chave "out" ou "ref" para tornar o parâmetro mutável. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf index fca13d2b25e7f6..3c763338f053c4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + Тип "{0}" будет рассматриваться как структура в собственной подписи, а не как собственный HRESULT. Чтобы обработать это как HRESULT, добавьте в метод "[return:MarshalAs(UnmanagedType.Error)]". This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Этот тип будет рассматриваться как структура в собственной подписи, а не как собственный HRESULT. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf index 44d2a4a4cbadd3..b3551845a81494 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + '{0}' türü, yerel HRESULT olarak değil, yerel imzada bir yapı olarak değerlendirilir. Bunu bir HRESULT olarak değerlendirmek için yönteme '[return:MarshalAs(UnmanagedType.Error)]' ekleyin. This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + Bu tür, yerel HRESULT olarak değil, yerel imzada bir yapı olarak değerlendirilir diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf index e6fbf9115aec2d..5f77e5d137a900 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + 类型“{0}”将被视为本机签名中的结构,而不是本机 HRESULT。若要将其视为 HRESULT,请将“[return:MarshalAs(UnmanagedType.Error)]”添加到方法。 This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + 此类型将被视为本机签名中的结构,而不是本机 HRESULT @@ -904,7 +904,7 @@ The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + `[Out]` 属性仅在数组参数上受支持。请考虑使用“out”或“ref”关键字使参数可变。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf index 528339678cefdb..30be4f574082e7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -439,12 +439,12 @@ The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. - The type '{0}' will be treated as a struct in the native signature, not as a native HRESULT. To treat this as an HRESULT, add '[return:MarshalAs(UnmanagedType.Error)]' to the method. + 類型 '{0}' 會被視為原生簽章中的結構,而非原生 HRESULT。若要將此視為 HRESULT,請將 '[return:MarshalAs(UnmanagedType.Error)]' 新增至方法。 This type will be treated as a struct in the native signature, not as a native HRESULT - This type will be treated as a struct in the native signature, not as a native HRESULT + 此類型會被視為原生簽章中的結構,而非原生 HRESULT diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf index 41ce7674876442..0911c52f6700e0 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - Zdrojový generátor System.Text.Json není k dispozici v jazyce C#{0}. Použijte prosím jazykovou verzi {1} nebo vyšší. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf index a0b49aa02c03f3..156d9972bb6799 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - Der System.Text.Json-Quellgenerator ist in C# „{0}“ nicht verfügbar. Verwenden Sie die Sprachversion {1} oder höher. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf index bdd7876fa38cd3..d609f70c4f02fb 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - El generador de origen System.Text.Json no está disponible en C# '{0}'. Use la versión de idioma {1} o superior. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf index 4b93e17edd6eb6..796b0000fa0973 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - Le générateur de source System.Text.Json n'est pas disponible en C# '{0}'. Veuillez utiliser la version linguistique {1} ou supérieure. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf index cb163ff94ec4f9..5c5f6a6d079979 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - Il generatore di origine System.Text.Json non è disponibile in C# '{0}'. Usare la versione del linguaggio {1} o successiva. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf index 9e3366a8bf09a2..b9b33f30c719c2 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - System.Text.Json ソース ジェネレーターは C# '{0}' では使用できません。言語バージョン {1} 以上を使用してください。 + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf index 735e6d772f7c26..4247e794b564a7 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - System.Text.Json 원본 생성기는 C# '{0}'에서 사용할 수 없습니다. {1} 이상의 언어 버전을 사용하세요. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf index 8282fa16aa908b..3ac0444fdee2a2 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - Generator źródła System.Text.Json nie jest dostępny w języku C# „{0}”. Użyj wersji językowej lub nowszej {1} . + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf index 030a3f3302e729..d351ab9fa8a9ab 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - O gerador de fonte System.Text.Json não está disponível em C# '{0}'. Use a versão do idioma {1} ou superior. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf index 556fa665267f30..35b0dfef2a6640 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - Генератор исходного кода System.Text.Json не доступен в C# "{0}". Используйте языковую версию {1} или выше. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf index e74d8818167e3d..8f9d470847a1b8 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - System.Text.Json kaynak oluşturucusu C# '{0}' içinde kullanılamıyor. Lütfen dil sürümü {1} veya üstü sürümü kullanın. + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf index 3ac4929b2b76dd..fc6ddb4af529ef 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - System.Text.Json 源生成器在 C#“{0}”中不可用。请使用{1}或更高版本的语言版本。 + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf index a194d8afc278d7..46c0ae9ab63087 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - C# '{0}' 中無法使用 System.Text.Json 來源產生器。請使用 {1} 或更新的語言版本。 + The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. From 2ed29ecfd1095220db73d17aec87a021ef39bac1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 08:39:38 -0700 Subject: [PATCH 071/345] Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230823.2 (#91057) Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23421.3 -> To Version 3.11.0-beta1.23423.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 77bab659bb6547..440d7a2fa84317 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -371,11 +371,11 @@ https://github.com/dotnet/roslyn 93ce610622875b8e843f348e96496abd7056360d - + https://github.com/dotnet/roslyn-analyzers 76d99c5f3e11f0600fae074270c0d89042c360f0 - + https://github.com/dotnet/roslyn-analyzers 76d99c5f3e11f0600fae074270c0d89042c360f0 diff --git a/eng/Versions.props b/eng/Versions.props index 8d8fb363926aed..d3c2fd7c97309a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.23421.3 - 8.0.0-preview.23421.3 + 3.11.0-beta1.23423.2 + 8.0.0-preview.23423.2 - 4.8.0-2.23422.14 - 4.8.0-2.23422.14 - 4.8.0-2.23422.14 + 4.8.0-2.23423.10 + 4.8.0-2.23423.10 + 4.8.0-2.23423.10 @@ -230,15 +230,6 @@ - - - <_MajorVersion>$([System.Version]::Parse('$(AssemblyVersion)').Major) - <_MinorVersion>$([System.Version]::Parse('$(AssemblyVersion)').Minor) - <_PatchVersion>$([System.Version]::Parse('$(AssemblyVersion)').Build) - <_BuildNumber>$([System.Version]::Parse('$(AssemblyVersion)').Revision) - - - 5 @@ -256,9 +247,9 @@ From f4120cc6972105809378f6800a75df6ea2a77aa9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 15:36:51 -0700 Subject: [PATCH 074/345] [release/8.0] `PEImage` should not permit `m_path` field mutation (#91085) * Remove cases where PEImage::m_path was mutated. Create m_pathHash field and remove function. Remove FEATURE_CASE_SENSITIVE_FILESYSTEM. * Address contract violations * Remove try/catch and replace with assert --------- Co-authored-by: Aaron R Robinson --- src/coreclr/debug/daccess/request.cpp | 3 +-- src/coreclr/inc/sstring.h | 2 ++ src/coreclr/md/compiler/mdutil.cpp | 8 ------- src/coreclr/vm/dwbucketmanager.hpp | 8 +++---- src/coreclr/vm/excep.cpp | 5 +++-- src/coreclr/vm/peimage.cpp | 10 +++------ src/coreclr/vm/peimage.h | 3 +-- src/coreclr/vm/peimage.inl | 32 ++------------------------- src/coreclr/vm/peimagelayout.cpp | 15 ++++++++++--- src/coreclr/vm/readytoruninfo.cpp | 7 +++--- 10 files changed, 31 insertions(+), 62 deletions(-) diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index 114900ffaf0365..e5cc22d8c708a5 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -2648,8 +2648,7 @@ ClrDataAccess::GetAssemblyLocation(CLRDATA_ADDRESS assembly, int count, _Inout_u // Turn from bytes to wide characters if (!pAssembly->GetPEAssembly()->GetPath().IsEmpty()) { - if (!pAssembly->GetPEAssembly()->GetPath(). - DacGetUnicode(count, location, pNeeded)) + if (!pAssembly->GetPEAssembly()->GetPath().DacGetUnicode(count, location, pNeeded)) { hr = E_FAIL; } diff --git a/src/coreclr/inc/sstring.h b/src/coreclr/inc/sstring.h index 00b826b23c3c54..6557ca0d43edb1 100644 --- a/src/coreclr/inc/sstring.h +++ b/src/coreclr/inc/sstring.h @@ -683,7 +683,9 @@ class EMPTY_BASES_DECL SString : private SBuffer BOOL IsASCIIScanned() const; void SetASCIIScanned() const; void SetNormalized() const; +public: BOOL IsNormalized() const; +private: void ClearNormalized() const; void EnsureWritable() const; diff --git a/src/coreclr/md/compiler/mdutil.cpp b/src/coreclr/md/compiler/mdutil.cpp index 8fb1551ef7ceea..05b56a25875bb0 100644 --- a/src/coreclr/md/compiler/mdutil.cpp +++ b/src/coreclr/md/compiler/mdutil.cpp @@ -265,11 +265,7 @@ HRESULT LOADEDMODULES::FindCachedReadOnlyEntry( { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); - #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM - if (u16_strcmp(szName, pszName) == 0) - #else if (SString::_wcsicmp(szName, pszName) == 0) - #endif { ULONG cRefs; @@ -299,11 +295,7 @@ HRESULT LOADEDMODULES::FindCachedReadOnlyEntry( { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); - #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM - if (u16_strcmp(szName, pszName) == 0) - #else if (SString::_wcsicmp(szName, pszName) == 0) - #endif { ULONG cRefs; diff --git a/src/coreclr/vm/dwbucketmanager.hpp b/src/coreclr/vm/dwbucketmanager.hpp index 167685f78a597c..82532aa5b42b4b 100644 --- a/src/coreclr/vm/dwbucketmanager.hpp +++ b/src/coreclr/vm/dwbucketmanager.hpp @@ -960,11 +960,9 @@ bool BaseBucketParamsManager::GetFileVersionInfoForModule(Module* pModule, USHOR // if we failed to get the version info from the native image then fall back to the IL image. if (!succeeded) { - LPCWSTR modulePath = pPEAssembly->GetPath().GetUnicode(); - if (modulePath != NULL && modulePath != SString::Empty() && SUCCEEDED(DwGetFileVersionInfo(modulePath, major, minor, build, revision))) - { - succeeded = true; - } + const SString& modulePath = pPEAssembly->GetPath(); + _ASSERTE(modulePath.IsNormalized()); + succeeded = !modulePath.IsEmpty() && SUCCEEDED(DwGetFileVersionInfo(modulePath.GetUnicode(), major, minor, build, revision)); } } diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 5be645ad496d7d..ce8b325a5f41b8 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -11616,7 +11616,8 @@ VOID GetAssemblyDetailInfo(SString &sType, SString sAlcName; pPEAssembly->GetAssemblyBinder()->GetNameForDiagnostics(sAlcName); - if (pPEAssembly->GetPath().IsEmpty()) + SString assemblyPath{ pPEAssembly->GetPath() }; + if (assemblyPath.IsEmpty()) { detailsUtf8.Printf("Type %s originates from '%s' in the context '%s' in a byte array", sType.GetUTF8(), @@ -11629,7 +11630,7 @@ VOID GetAssemblyDetailInfo(SString &sType, sType.GetUTF8(), sAssemblyDisplayName.GetUTF8(), sAlcName.GetUTF8(), - pPEAssembly->GetPath().GetUTF8()); + assemblyPath.GetUTF8()); } sAssemblyDetailInfo.Append(detailsUtf8.GetUnicode()); diff --git a/src/coreclr/vm/peimage.cpp b/src/coreclr/vm/peimage.cpp index 55fc458c83762c..656b42b8111c70 100644 --- a/src/coreclr/vm/peimage.cpp +++ b/src/coreclr/vm/peimage.cpp @@ -141,11 +141,11 @@ ULONG PEImage::Release() result=InterlockedDecrement(&m_refCount); if (result == 0 ) { - LOG((LF_LOADER, LL_INFO100, "PEImage: Closing Image %s\n", m_path.GetUTF8())); + LOG((LF_LOADER, LL_INFO100, "PEImage: Closing %p\n", this)); if(m_bInHashMap) { PEImageLocator locator(this); - PEImage* deleted = (PEImage *)s_Images->DeleteValue(GetPathHash(), &locator); + PEImage* deleted = (PEImage *)s_Images->DeleteValue(m_pathHash, &locator); _ASSERTE(deleted == this); } } @@ -249,12 +249,7 @@ BOOL PEImage::CompareImage(UPTR u1, UPTR u2) EX_TRY { SString path(SString::Literal, pLocator->m_pPath); - -#ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM - if (pImage->GetPath().Equals(path)) -#else if (pImage->GetPath().EqualsCaseInsensitive(path)) -#endif { ret = TRUE; } @@ -623,6 +618,7 @@ void PEImage::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) PEImage::PEImage(): m_path(), + m_pathHash(0), m_refCount(1), m_bInHashMap(FALSE), m_bundleFileLocation(), diff --git a/src/coreclr/vm/peimage.h b/src/coreclr/vm/peimage.h index d30e561890c79e..e7bfc11d319f12 100644 --- a/src/coreclr/vm/peimage.h +++ b/src/coreclr/vm/peimage.h @@ -132,8 +132,6 @@ class PEImage final PTR_PEImageLayout GetLoadedLayout(); PTR_PEImageLayout GetFlatLayout(); - BOOL HasPath(); - ULONG GetPathHash(); const SString& GetPath(); const SString& GetPathToLoad(); LPCWSTR GetPathForErrorMessages() { return GetPath(); } @@ -288,6 +286,7 @@ class PEImage final // ------------------------------------------------------------ SString m_path; + ULONG m_pathHash; LONG m_refCount; // means this is a unique (deduped) instance. diff --git a/src/coreclr/vm/peimage.inl b/src/coreclr/vm/peimage.inl index 6bb3c9320cb5f0..d17d5d9dd77387 100644 --- a/src/coreclr/vm/peimage.inl +++ b/src/coreclr/vm/peimage.inl @@ -288,6 +288,7 @@ inline void PEImage::Init(LPCWSTR pPath, BundleFileLocation bundleFileLocation) m_path = pPath; m_path.Normalize(); + m_pathHash = m_path.HashCaseInsensitive(); m_bundleFileLocation = bundleFileLocation; SetModuleFileNameHintForDAC(); } @@ -310,11 +311,7 @@ inline PTR_PEImage PEImage::FindByPath(LPCWSTR pPath, BOOL isInBundle /* = TRUE int CaseHashHelper(const WCHAR *buffer, COUNT_T count); PEImageLocator locator(pPath, isInBundle); -#ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM - DWORD dwHash=path.Hash(); -#else DWORD dwHash = CaseHashHelper(pPath, (COUNT_T) u16_strlen(pPath)); -#endif return (PEImage *) s_Images->LookupValue(dwHash, &locator); } @@ -366,7 +363,7 @@ inline void PEImage::AddToHashMap() CONTRACTL_END; _ASSERTE(s_hashLock.OwnedByCurrentThread()); - s_Images->InsertValue(GetPathHash(),this); + s_Images->InsertValue(m_pathHash,this); m_bInHashMap=TRUE; } @@ -378,31 +375,6 @@ inline BOOL PEImage::Has32BitNTHeaders() return GetOrCreateLayout(PEImageLayout::LAYOUT_ANY)->Has32BitNTHeaders(); } -inline BOOL PEImage::HasPath() -{ - LIMITED_METHOD_CONTRACT; - - return !GetPath().IsEmpty(); -} - -inline ULONG PEImage::GetPathHash() -{ - CONTRACT(ULONG) - { - PRECONDITION(HasPath()); - MODE_ANY; - GC_NOTRIGGER; - THROWS; - } - CONTRACT_END; - -#ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM - RETURN m_path.Hash(); -#else - RETURN m_path.HashCaseInsensitive(); -#endif -} - inline void PEImage::GetPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine) { CONTRACTL diff --git a/src/coreclr/vm/peimagelayout.cpp b/src/coreclr/vm/peimagelayout.cpp index c756c451649b34..0f0dde27618196 100644 --- a/src/coreclr/vm/peimagelayout.cpp +++ b/src/coreclr/vm/peimagelayout.cpp @@ -534,7 +534,10 @@ LoadedImageLayout::LoadedImageLayout(PEImage* pOwner, HRESULT* loadFailure) IfFailThrow(Init(m_Module, true)); - LOG((LF_LOADER, LL_INFO1000, "PEImage: Opened HMODULE %s\n", pOwner->GetPath().GetUTF8())); +#ifdef LOGGING + SString ownerPath{ pOwner->GetPath() }; + LOG((LF_LOADER, LL_INFO1000, "PEImage: Opened HMODULE %s\n", ownerPath.GetUTF8())); +#endif // LOGGING #else HANDLE hFile = pOwner->GetFileHandle(); @@ -548,8 +551,11 @@ LoadedImageLayout::LoadedImageLayout(PEImage* pOwner, HRESULT* loadFailure) return; } +#ifdef LOGGING + SString ownerPath{ pOwner->GetPath() }; LOG((LF_LOADER, LL_INFO1000, "PEImage: image %s (hFile %p) mapped @ %p\n", - pOwner->GetPath().GetUTF8(), hFile, (void*)m_LoadedFile)); + ownerPath.GetUTF8(), hFile, (void*)m_LoadedFile)); +#endif // LOGGING IfFailThrow(Init((void*)m_LoadedFile)); @@ -616,7 +622,10 @@ FlatImageLayout::FlatImageLayout(PEImage* pOwner) INT64 offset = pOwner->GetOffset(); INT64 size = pOwner->GetSize(); - LOG((LF_LOADER, LL_INFO100, "PEImage: Opening flat %s\n", pOwner->GetPath().GetUTF8())); +#ifdef LOGGING + SString ownerPath{ pOwner->GetPath() }; + LOG((LF_LOADER, LL_INFO100, "PEImage: Opening flat %s\n", ownerPath.GetUTF8())); +#endif // LOGGING // If a size is not specified, load the whole file if (size == 0) diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index 2c186cf7adeaff..e75373db8855aa 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -429,7 +429,8 @@ static void LogR2r(const char *msg, PEAssembly *pPEAssembly) if (r2rLogFile == NULL) return; - fprintf(r2rLogFile, "%s: \"%s\".\n", msg, pPEAssembly->GetPath().GetUTF8()); + SString assemblyPath{ pPEAssembly->GetPath() }; + fprintf(r2rLogFile, "%s: \"%s\".\n", msg, assemblyPath.GetUTF8()); fflush(r2rLogFile); } @@ -1904,7 +1905,7 @@ uint32_t ReadyToRun_TypeGenericInfoMap::GetGenericArgumentCount(mdTypeDef input, uint32_t count = ((uint8_t)typeGenericInfo & (uint8_t)ReadyToRunTypeGenericInfo::GenericCountMask); if (count > 2) foundResult = false; - + if (!foundResult) { HENUMInternalHolder hEnumTyPars(pImport); @@ -1922,7 +1923,7 @@ HRESULT ReadyToRun_TypeGenericInfoMap::GetGenericArgumentCountNoThrow(mdTypeDef uint32_t count = ((uint8_t)typeGenericInfo & (uint8_t)ReadyToRunTypeGenericInfo::GenericCountMask); if (count > 2) foundResult = false; - + if (!foundResult) { HENUMInternalHolder hEnumTyPars(pImport); From a1b75718cf9af2d48178676b587dc632d4a47579 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Thu, 24 Aug 2023 16:13:15 -0700 Subject: [PATCH 075/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2251942 (#91082) * Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2251732 * Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2251732 --- .../gen/Resources/xlf/Strings.cs.xlf | 2 +- .../gen/Resources/xlf/Strings.de.xlf | 2 +- .../gen/Resources/xlf/Strings.es.xlf | 2 +- .../gen/Resources/xlf/Strings.fr.xlf | 2 +- .../gen/Resources/xlf/Strings.it.xlf | 2 +- .../gen/Resources/xlf/Strings.ja.xlf | 2 +- .../gen/Resources/xlf/Strings.ko.xlf | 2 +- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 2 +- .../gen/Resources/xlf/Strings.ru.xlf | 2 +- .../gen/Resources/xlf/Strings.tr.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- .../gen/Resources/xlf/Strings.cs.xlf | 2 +- .../gen/Resources/xlf/Strings.de.xlf | 2 +- .../gen/Resources/xlf/Strings.es.xlf | 2 +- .../gen/Resources/xlf/Strings.fr.xlf | 2 +- .../gen/Resources/xlf/Strings.it.xlf | 2 +- .../gen/Resources/xlf/Strings.ja.xlf | 2 +- .../gen/Resources/xlf/Strings.ko.xlf | 2 +- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 2 +- .../gen/Resources/xlf/Strings.ru.xlf | 2 +- .../gen/Resources/xlf/Strings.tr.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- .../System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf | 2 +- 27 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf index 00e8b1cc7d91a1..37788ebcb678e0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.cs.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Zdrojový generátor nepodporuje jazykovou verzi jazyka C#. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf index 2e962cd97ac902..9ab54f800fbbca 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.de.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Die C#-Sprachversion wird vom Quellgenerator nicht unterstützt. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf index 46073f102868a1..338324b076f41d 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.es.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + La versión del idioma C# no es compatible con el generador de origen. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf index 2497ea11a88a04..13e61bd2e4a5e9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.fr.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Version du langage C# non prise en charge par le générateur de source. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf index 06dadffd497939..8cf28e310dc03f 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.it.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Versione del linguaggio C# non supportata dal generatore di origine. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf index bd03905bfba997..6c9b4d737bbaea 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ja.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + ソース ジェネレーターでサポートされていない C# 言語バージョン。 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf index eea8ef2203ac1d..f38d678fa54e79 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ko.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + 원본 생성기에서 지원되지 않는 C# 언어 버전입니다. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf index 6dbecb86f7fc43..b7c27d6dc5a24b 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Wersja języka C# nie jest obsługiwana przez generator źródła. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf index f7de3a39c5a055..bc05308fa051b9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pt-BR.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Versão da linguagem C# não suportada pelo gerador de origem. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf index 9599e0f6b9b809..2136e696d079a3 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.ru.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Версия языка C# не поддерживается генератором исходного кода. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf index 529a109ef75304..357b981c7f4f90 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.tr.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + C# dil sürümü kaynak oluşturucu tarafından desteklenmiyor. diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf index 879c6a773643a1..e9b74ddd39a10f 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -74,7 +74,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + 源生成器不支持 C# 语言版本。 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf index 42061caa455c27..cac7d73e8e5d6a 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -69,12 +69,12 @@ The Logging source generator is not available in C# {0}. Please use language version {1} or greater. - The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + C# {0} 無法使用記錄來源產生器。請使用 {1} 或更新的語言版本。 C# language version not supported by the source generator. - C# language version not supported by the source generator. + 來源產生器不支援 C# 語言版本。 diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf index cf1eaeedf07021..43818442898af7 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.cs.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Zdrojový generátor nepodporuje jazykovou verzi jazyka C#. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf index 507e5896457a51..bee47d77cb69b6 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.de.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Die C#-Sprachversion wird vom Quellgenerator nicht unterstützt. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf index 4ee57aa7312aa0..1c99ae4dbe8287 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.es.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + La versión del idioma C# no es compatible con el generador de origen. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf index 9e300eaed00812..ca8683e6a65f19 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.fr.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Version du langage C# non prise en charge par le générateur de source. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf index f59cc9dcbeeefb..fd07503323fbd1 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.it.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Versione del linguaggio C# non supportata dal generatore di origine. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf index 72a828f97c5e29..c1e4e390fa59ce 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ja.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + ソース ジェネレーターでサポートされていない C# 言語バージョン。 diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf index 9018aaf6993610..a93c8b1b555880 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ko.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + 원본 생성기에서 지원되지 않는 C# 언어 버전입니다. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf index 126471f22a6c9e..5949f6a902609b 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Wersja języka C# nie jest obsługiwana przez generator źródła. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf index dcc8db9dcbefe4..a2d117a7d285f8 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pt-BR.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Versão da linguagem C# não suportada pelo gerador de origem. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf index c1fd957bf6c53d..bd9e7c4ae55b00 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.ru.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + Версия языка C# не поддерживается генератором исходного кода. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf index 4adda20ccd1581..82a8e29cb42c31 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.tr.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + C# dil sürümü kaynak oluşturucu tarafından desteklenmiyor. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf index 4a6d79badc79f4..cedd65965409b6 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -129,7 +129,7 @@ C# language version not supported by the source generator. - C# language version not supported by the source generator. + 源生成器不支持 C# 语言版本。 diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf index f0d9a24cdfb1eb..0180ca96648f19 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -124,12 +124,12 @@ The options validation source generator is not available in C# {0}. Please use language version {1} or greater. - The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + C# {0} 無法使用選項驗證來源產生器。請使用 {1} 或更新的語言版本。 C# language version not supported by the source generator. - C# language version not supported by the source generator. + 來源產生器不支援 C# 語言版本。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf index 46c0ae9ab63087..ed207add481d94 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + C# {0} 中無法使用 System.Text.Json 來源產生器。請使用 {1} 或更新的語言版本。 From 12c5dd7180c92bb59460f0d1eb7587e3d44ed5f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 16:14:26 -0700 Subject: [PATCH 076/345] Suppress credscan warnings in X.509 test files (#91080) Co-authored-by: Levi Broderick --- .../tests/X509Certificates/TestData.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs index 7110c78329778d..e3deb00b354d06 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/TestData.cs @@ -51,7 +51,8 @@ internal static class TestData // This pfx was generated by new X509Certificate(MsCertificate).Export(X509ContentType.Pfx) // and was choosen when the padding was 01 and caused a false-positive on decryption. - public static byte[] MsCertificateExportedToPfx_NullPassword = Convert.FromBase64String(@" + public static byte[] MsCertificateExportedToPfx_NullPassword = Convert.FromBase64String( + /* [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="This PKCS#12 blob only contains public info.")] */ @" MIIFxAIBAzCCBYoGCSqGSIb3DQEHAaCCBXsEggV3MIIFczCCBW8GCSqGSIb3DQEH BqCCBWAwggVcAgEAMIIFVQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIKpCU u5nlxAACAggAgIIFKG/SLlS1TJmxGUiXBPJ1r4yV+JMehwo6RYPMkCSnpKGaiLyA @@ -3057,7 +3058,8 @@ internal static DSAParameters GetDSA1024Params() "4D7314FCB4041469835268466D1390373566F7034C4736346CD17D020207D0").HexToByteArray(); internal static readonly byte[] Pkcs12NoPasswordRandomCounts = - Convert.FromBase64String(@" + Convert.FromBase64String( + /* [SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Self-signed cert created specifically for inclusion in public-facing unit tests.")] */ @" MIIvdAIBAzCCLtQGCSqGSIb3DQEHAaCCLsUEgi7BMIIuvTCCLrkGCSqGSIb3DQEHAaCCLqoEgi6m MIIuojCCAvkGCyqGSIb3DQEMCgECoIIC6DCCAuQwXgYJKoZIhvcNAQUNMFEwMAYJKoZIhvcNAQUM MCMEELD+7LV5Y9tyUiJnNeZVLwQCASowDAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEBzHfelA From 06c76d6f5f6d725a7e03e65da4db58191c8a8c1b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 16:24:40 -0700 Subject: [PATCH 077/345] Fix JIT_ByRefWriteBarrier unwinding on macOS x64 (#91076) Local labels in the JIT_ByRefWriteBarrier were not wrapped in the LOCAL_LABEL macro. That causes incorrect unwinding in case an access violation occurs inside of this function. The closest label before the failure point is considered to be the actual function, but it obviously doesn't have the right unwind info. Close #89585 Co-authored-by: Jan Vorlicek --- src/coreclr/vm/amd64/jithelpers_fast.S | 98 +++++++++++++------------- src/tests/issues.targets | 4 +- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/coreclr/vm/amd64/jithelpers_fast.S b/src/coreclr/vm/amd64/jithelpers_fast.S index 32890b471b26c1..72f91a18061579 100644 --- a/src/coreclr/vm/amd64/jithelpers_fast.S +++ b/src/coreclr/vm/amd64/jithelpers_fast.S @@ -32,16 +32,16 @@ LEAF_ENTRY JIT_CheckedWriteBarrier, _TEXT // See if this is in GCHeap PREPARE_EXTERNAL_VAR g_lowest_address, rax cmp rdi, [rax] - // jb NotInHeap + // jb LOCAL_LABEL(NotInHeap) .byte 0x72, 0x12 PREPARE_EXTERNAL_VAR g_highest_address, rax cmp rdi, [rax] - // jnb NotInHeap + // jnb LOCAL_LABEL(NotInHeap) .byte 0x73, 0x06 jmp [rip + C_FUNC(JIT_WriteBarrier_Loc)] - NotInHeap: + LOCAL_LABEL(NotInHeap): // See comment above about possible AV mov [rdi], rsi ret @@ -85,16 +85,16 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT add rax, r10 cmp byte ptr [rax], 0x0 .byte 0x75, 0x06 - // jne CheckCardTable + // jne LOCAL_LABEL(CheckCardTable) mov byte ptr [rax], 0xFF NOP_3_BYTE // padding for alignment of constant // Check the lower and upper ephemeral region bounds - CheckCardTable: + LOCAL_LABEL(CheckCardTable): cmp rsi, r11 .byte 0x72,0x3D - // jb Exit + // jb LOCAL_LABEL(Exit) NOP_3_BYTE // padding for alignment of constant @@ -102,7 +102,7 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT cmp rsi, r10 .byte 0x73,0x2B - // jae Exit + // jae LOCAL_LABEL(Exit) nop // padding for alignment of constant @@ -112,10 +112,10 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT shr rdi, 0x0B cmp byte ptr [rdi + rax], 0xFF .byte 0x75, 0x02 - // jne UpdateCardTable + // jne LOCAL_LABEL(UpdateCardTable) REPRET - UpdateCardTable: + LOCAL_LABEL(UpdateCardTable): mov byte ptr [rdi + rax], 0xFF #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES @@ -126,17 +126,17 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT cmp byte ptr [rdi + rax], 0xFF .byte 0x75, 0x02 - // jne UpdateCardBundle_WriteWatch_PostGrow64 + // jne LOCAL_LABEL(UpdateCardBundle_WriteWatch_PostGrow64) REPRET - UpdateCardBundle_WriteWatch_PostGrow64: + LOCAL_LABEL(UpdateCardBundle_WriteWatch_PostGrow64): mov byte ptr [rdi + rax], 0xFF #endif ret .balign 16 - Exit: + LOCAL_LABEL(Exit): REPRET NOP_3_BYTE @@ -184,7 +184,7 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT // Check the lower and upper ephemeral region bounds cmp rsi, rax - // jb Exit + // jb LOCAL_LABEL(Exit) .byte 0x72, 0x36 nop // padding for alignment of constant @@ -192,7 +192,7 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT movabs r8, 0xF0F0F0F0F0F0F0F0 cmp rsi, r8 - // jae Exit + // jae LOCAL_LABEL(Exit) .byte 0x73, 0x26 nop // padding for alignment of constant @@ -203,10 +203,10 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT shr rdi, 0Bh cmp byte ptr [rdi + rax], 0FFh .byte 0x75, 0x02 - // jne UpdateCardTable + // jne LOCAL_LABEL(UpdateCardTable) REPRET - UpdateCardTable: + LOCAL_LABEL(UpdateCardTable): mov byte ptr [rdi + rax], 0FFh #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES @@ -220,17 +220,17 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT cmp byte ptr [rdi + rax], 0FFh .byte 0x75, 0x02 - // jne UpdateCardBundle + // jne LOCAL_LABEL(UpdateCardBundle) REPRET - UpdateCardBundle: + LOCAL_LABEL(UpdateCardBundle): mov byte ptr [rdi + rax], 0FFh #endif ret .balign 16 - Exit: + LOCAL_LABEL(Exit): REPRET #endif @@ -277,30 +277,30 @@ LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT // See if this is in GCHeap PREPARE_EXTERNAL_VAR g_lowest_address, rax cmp rdi, [rax] - jb NotInHeap_ByRefWriteBarrier + jb LOCAL_LABEL(NotInHeap_ByRefWriteBarrier) PREPARE_EXTERNAL_VAR g_highest_address, rax cmp rdi, [rax] - jnb NotInHeap_ByRefWriteBarrier + jnb LOCAL_LABEL(NotInHeap_ByRefWriteBarrier) #ifdef WRITE_BARRIER_CHECK // **ALSO update the shadow GC heap if that is enabled** // Do not perform the work if g_GCShadow is 0 PREPARE_EXTERNAL_VAR g_GCShadow, rax cmp qword ptr [rax], 0 - je NoShadow_ByRefWriteBarrier + je LOCAL_LABEL(NoShadow_ByRefWriteBarrier) // If we end up outside of the heap don't corrupt random memory mov r10, rdi PREPARE_EXTERNAL_VAR g_lowest_address, rax sub r10, [rax] - jb NoShadow_ByRefWriteBarrier + jb LOCAL_LABEL(NoShadow_ByRefWriteBarrier) // Check that our adjusted destination is somewhere in the shadow gc PREPARE_EXTERNAL_VAR g_GCShadow, rax add r10, [rax] PREPARE_EXTERNAL_VAR g_GCShadowEnd, rax cmp r10, [rax] - jnb NoShadow_ByRefWriteBarrier + jnb LOCAL_LABEL(NoShadow_ByRefWriteBarrier) // Write ref into real GC mov [rdi], rcx @@ -315,73 +315,73 @@ LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT mov r11, [rdi] mov rax, [r10] cmp rax, r11 - je DoneShadow_ByRefWriteBarrier + je LOCAL_LABEL(DoneShadow_ByRefWriteBarrier) movabs r11, INVALIDGCVALUE mov [r10], r11 - jmp DoneShadow_ByRefWriteBarrier + jmp LOCAL_LABEL(DoneShadow_ByRefWriteBarrier) // If we don't have a shadow GC we won't have done the write yet - NoShadow_ByRefWriteBarrier: + LOCAL_LABEL(NoShadow_ByRefWriteBarrier): mov [rdi], rcx // If we had a shadow GC then we already wrote to the real GC at the same time // as the shadow GC so we want to jump over the real write immediately above. // Additionally we know for sure that we are inside the heap and therefore don't // need to replicate the above checks. - DoneShadow_ByRefWriteBarrier: + LOCAL_LABEL(DoneShadow_ByRefWriteBarrier): #endif #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP // Update the write watch table if necessary PREPARE_EXTERNAL_VAR g_sw_ww_enabled_for_gc_heap, rax cmp byte ptr [rax], 0x0 - je CheckCardTable_ByRefWriteBarrier + je LOCAL_LABEL(CheckCardTable_ByRefWriteBarrier) mov rax, rdi shr rax, 0xC // SoftwareWriteWatch::AddressToTableByteIndexShift PREPARE_EXTERNAL_VAR g_sw_ww_table, r10 add rax, qword ptr [r10] cmp byte ptr [rax], 0x0 - jne CheckCardTable_ByRefWriteBarrier + jne LOCAL_LABEL(CheckCardTable_ByRefWriteBarrier) mov byte ptr [rax], 0xFF #endif - CheckCardTable_ByRefWriteBarrier: + LOCAL_LABEL(CheckCardTable_ByRefWriteBarrier): // See if we can just quick out PREPARE_EXTERNAL_VAR g_ephemeral_low, rax cmp rcx, [rax] - jb Exit_ByRefWriteBarrier + jb LOCAL_LABEL(Exit_ByRefWriteBarrier) PREPARE_EXTERNAL_VAR g_ephemeral_high, rax cmp rcx, [rax] - jnb Exit_ByRefWriteBarrier + jnb LOCAL_LABEL(Exit_ByRefWriteBarrier) mov rax, rcx PREPARE_EXTERNAL_VAR g_region_shr, rcx mov cl, [rcx] test cl, cl - je SkipCheck_ByRefWriteBarrier + je LOCAL_LABEL(SkipCheck_ByRefWriteBarrier) // check if the source is in gen 2 - then it's not an ephemeral pointer shr rax, cl PREPARE_EXTERNAL_VAR g_region_to_generation_table, r10 mov r10, [r10] cmp byte ptr [rax + r10], 0x82 - je Exit_ByRefWriteBarrier + je LOCAL_LABEL(Exit_ByRefWriteBarrier) // check if the destination happens to be in gen 0 mov rax, rdi shr rax, cl cmp byte ptr [rax + r10], 0 - je Exit_ByRefWriteBarrier - SkipCheck_ByRefWriteBarrier: + je LOCAL_LABEL(Exit_ByRefWriteBarrier) + LOCAL_LABEL(SkipCheck_ByRefWriteBarrier): PREPARE_EXTERNAL_VAR g_card_table, r10 mov r10, [r10] PREPARE_EXTERNAL_VAR g_region_use_bitwise_write_barrier, rax cmp byte ptr [rax], 0 - je CheckCardTableByte_ByRefWriteBarrier + je LOCAL_LABEL(CheckCardTableByte_ByRefWriteBarrier) // compute card table bit mov ecx, edi @@ -400,15 +400,15 @@ LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT shr rcx, 0xB // Check if this card table bit is already set test byte ptr [rcx + r10], al - je SetCardTableBit_ByRefWriteBarrier + je LOCAL_LABEL(SetCardTableBit_ByRefWriteBarrier) REPRET - SetCardTableBit_ByRefWriteBarrier: + LOCAL_LABEL(SetCardTableBit_ByRefWriteBarrier): lock or byte ptr [rcx + r10], al - jmp CheckCardBundle_ByRefWriteBarrier + jmp LOCAL_LABEL(CheckCardBundle_ByRefWriteBarrier) - CheckCardTableByte_ByRefWriteBarrier: + LOCAL_LABEL(CheckCardTableByte_ByRefWriteBarrier): // move current rdi value into rcx and then increment the pointers mov rcx, rdi add rsi, 0x8 @@ -416,12 +416,12 @@ LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT shr rcx, 0xB cmp byte ptr [rcx + r10], 0xFF - jne SetCardTableByte_ByRefWriteBarrier + jne LOCAL_LABEL(SetCardTableByte_ByRefWriteBarrier) REPRET - SetCardTableByte_ByRefWriteBarrier: + LOCAL_LABEL(SetCardTableByte_ByRefWriteBarrier): mov byte ptr [rcx + r10], 0xFF - CheckCardBundle_ByRefWriteBarrier: + LOCAL_LABEL(CheckCardBundle_ByRefWriteBarrier): #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES // Shift rcx by 0x0A more to get the card bundle byte (we shifted by 0x0B already) @@ -433,17 +433,17 @@ LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT // Check if this bundle byte is dirty cmp byte ptr [rcx], 0xFF - jne UpdateCardBundle_ByRefWriteBarrier + jne LOCAL_LABEL(UpdateCardBundle_ByRefWriteBarrier) REPRET - UpdateCardBundle_ByRefWriteBarrier: + LOCAL_LABEL(UpdateCardBundle_ByRefWriteBarrier): mov byte ptr [rcx], 0xFF #endif ret .balign 16 - NotInHeap_ByRefWriteBarrier: + LOCAL_LABEL(NotInHeap_ByRefWriteBarrier): // If WRITE_BARRIER_CHECK then we won't have already done the mov and should do it here // If !WRITE_BARRIER_CHECK we want _NotInHeap and _Leave to be the same and have both // 16 byte aligned. @@ -451,7 +451,7 @@ LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT // rcx is [rsi] mov [rdi], rcx #endif - Exit_ByRefWriteBarrier: + LOCAL_LABEL(Exit_ByRefWriteBarrier): // Increment the pointers before leaving add rdi, 0x8 add rsi, 0x8 diff --git a/src/tests/issues.targets b/src/tests/issues.targets index bdccec81ac1f49..b867b9134b5732 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -72,8 +72,8 @@ https://github.com/dotnet/runtime/issues/78899 - - https://github.com/dotnet/runtime/issues/89585 + + https://github.com/dotnet/runtime/issues/88586 From 562a16a22b79b9eaf15377f1a7c2d7b8a2339656 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:09:46 -0700 Subject: [PATCH 078/345] [release/8.0] Fix calling existing ctor with MethodInvoker; share tests with invokers (#90968) * Fix calling existing ctor with MethodInvoker; share tests with invokers * Remove unnecessary semicolon (non functional) --------- Co-authored-by: Steve Harter --- .../System/Reflection/ConstructorInvoker.cs | 2 +- .../src/System/Reflection/MethodInvoker.cs | 9 +- .../System/Reflection/MethodInvokerCommon.cs | 19 +- .../tests/ConstructorCommonTests.cs | 167 ++++++++++ .../tests/ConstructorInfoTests.cs | 169 ++-------- .../tests/ConstructorInvokerTests.cs | 30 +- .../System.Reflection.InvokeEmit.Tests.csproj | 4 + ....Reflection.InvokeInterpreted.Tests.csproj | 4 + .../tests/MethodCommonTests.cs | 297 ++++++++++++++++++ .../tests/MethodInfoTests.cs | 292 +---------------- .../tests/MethodInvokerTests.cs | 18 +- .../tests/System.Reflection.Tests.csproj | 14 +- 12 files changed, 574 insertions(+), 451 deletions(-) create mode 100644 src/libraries/System.Reflection/tests/ConstructorCommonTests.cs create mode 100644 src/libraries/System.Reflection/tests/MethodCommonTests.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs index 7f3c1a227e3718..3fad9dc8dba85f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs @@ -155,7 +155,7 @@ public object Invoke(object? arg1, object? arg2, object? arg3, object? arg4) private object InvokeImpl(object? arg1, object? arg2, object? arg3, object? arg4) { - if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers)) != 0) + if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers | InvocationFlags.NoConstructorInvoke)) != 0) { _method.ThrowNoInvokeException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs index 66a35dbd39c74b..0c8d9c59580703 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs @@ -66,7 +66,12 @@ public static MethodInvoker Create(MethodBase method) { // This is useful for calling a constructor on an already-initialized object // such as created from RuntimeHelpers.GetUninitializedObject(Type). - return new MethodInvoker(rci); + MethodInvoker invoker = new MethodInvoker(rci); + + // Use the interpreted version to avoid having to generate a new method that doesn't allocate. + invoker._strategy = GetStrategyForUsingInterpreted(); + + return invoker; } throw new ArgumentException(SR.Argument_MustBeRuntimeMethod, nameof(method)); @@ -181,7 +186,7 @@ private MethodInvoker(MethodBase method, RuntimeType[] argumentTypes) private object? InvokeImpl(object? obj, object? arg1, object? arg2, object? arg3, object? arg4) { - if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers)) != 0) + if ((_invocationFlags & (InvocationFlags.NoInvoke | InvocationFlags.ContainsStackPointers | InvocationFlags.NoConstructorInvoke)) != 0) { ThrowForBadInvocationFlags(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs index 191228b688faa1..813e89f80f8349 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvokerCommon.cs @@ -18,13 +18,14 @@ internal static void Initialize( { if (LocalAppContextSwitches.ForceInterpretedInvoke && !LocalAppContextSwitches.ForceEmitInvoke) { - // Always use the native invoke; useful for testing. - strategy = InvokerStrategy.StrategyDetermined_Obj4Args | InvokerStrategy.StrategyDetermined_ObjSpanArgs | InvokerStrategy.StrategyDetermined_RefArgs; + // Always use the native interpreted invoke. + // Useful for testing, to avoid startup overhead of emit, or for calling a ctor on already initialized object. + strategy = GetStrategyForUsingInterpreted(); } else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke) { // Always use emit invoke (if IsDynamicCodeSupported == true); useful for testing. - strategy = InvokerStrategy.HasBeenInvoked_Obj4Args | InvokerStrategy.HasBeenInvoked_ObjSpanArgs | InvokerStrategy.HasBeenInvoked_RefArgs; + strategy = GetStrategyForUsingEmit(); } else { @@ -69,6 +70,18 @@ internal static void Initialize( } } + internal static InvokerStrategy GetStrategyForUsingInterpreted() + { + // This causes the default strategy, which is interpreted, to always be used. + return InvokerStrategy.StrategyDetermined_Obj4Args | InvokerStrategy.StrategyDetermined_ObjSpanArgs | InvokerStrategy.StrategyDetermined_RefArgs; + } + + private static InvokerStrategy GetStrategyForUsingEmit() + { + // This causes the emit strategy, if supported, to be used on the first call as well as subsequent calls. + return InvokerStrategy.HasBeenInvoked_Obj4Args | InvokerStrategy.HasBeenInvoked_ObjSpanArgs | InvokerStrategy.HasBeenInvoked_RefArgs; + } + /// /// Confirm member invocation has an instance and is of the correct type /// diff --git a/src/libraries/System.Reflection/tests/ConstructorCommonTests.cs b/src/libraries/System.Reflection/tests/ConstructorCommonTests.cs new file mode 100644 index 00000000000000..5c71f79da014c1 --- /dev/null +++ b/src/libraries/System.Reflection/tests/ConstructorCommonTests.cs @@ -0,0 +1,167 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using Xunit; + +namespace System.Reflection.Tests +{ + /// + /// These tests are shared with ConstructorInfo.Invoke and ConstructorInvoker.Invoke by using + /// the abstract Invoke(...) methods below. + /// + public abstract class ConstructorCommonTests + { + public abstract object Invoke(ConstructorInfo constructorInfo, object?[]? parameters); + + protected abstract bool IsExceptionWrapped { get; } + + /// + /// Invoke constructor on an existing instance. Should return null. + /// + public abstract object? Invoke(ConstructorInfo constructorInfo, object obj, object?[]? parameters); + + public static ConstructorInfo[] GetConstructors(Type type) + { + return type.GetTypeInfo().DeclaredConstructors.ToArray(); + } + + [Fact] + public void SimpleInvoke() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + Assert.Equal(3, constructors.Length); + ClassWith3Constructors obj = (ClassWith3Constructors)Invoke(constructors[0], null); + Assert.NotNull(obj); + } + + [Fact] + [ActiveIssue("https://github.com/mono/mono/issues/15024", TestRuntimes.Mono)] + public void Invoke_StaticConstructor_ThrowsMemberAccessException() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWithStaticConstructor)); + Assert.Equal(1, constructors.Length); + Assert.Throws(() => Invoke(constructors[0], new object[0])); + } + + [Fact] + public void Invoke_OneDimensionalArray() + { + ConstructorInfo[] constructors = GetConstructors(typeof(object[])); + int[] arraylength = { 1, 2, 99, 65535 }; + + // Try to invoke Array ctors with different lengths + foreach (int length in arraylength) + { + // Create big Array with elements + object[] arr = (object[])Invoke(constructors[0], new object[] { length }); + Assert.Equal(arr.Length, length); + } + } + + [Fact] + public void Invoke_OneDimensionalArray_NegativeLengths_ThrowsOverflowException() + { + ConstructorInfo[] constructors = GetConstructors(typeof(object[])); + int[] arraylength = new int[] { -1, -2, -99 }; + // Try to invoke Array ctors with different lengths + foreach (int length in arraylength) + { + // Create big Array with elements + if (IsExceptionWrapped) + { + Exception ex = Assert.Throws(() => Invoke(constructors[0], new object[] { length })); + Assert.IsType(ex.InnerException); + } + else + { + Assert.Throws(() => Invoke(constructors[0], new object[] { length })); + } + } + } + + [Fact] + public void Invoke_OneParameter() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + ClassWith3Constructors obj = (ClassWith3Constructors)Invoke(constructors[1], new object[] { 100 }); + Assert.Equal(100, obj.intValue); + } + + [Fact] + public void Invoke_TwoParameters() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + ClassWith3Constructors obj = (ClassWith3Constructors)Invoke(constructors[2], new object[] { 101, "hello" }); + Assert.Equal(101, obj.intValue); + Assert.Equal("hello", obj.stringValue); + } + + [Fact] + public void Invoke_NoParameters_ThowsTargetParameterCountException() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + Assert.Throws(() => Invoke(constructors[2], new object[0])); + } + + [Fact] + public void Invoke_ParameterMismatch_ThrowsTargetParameterCountException() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + Assert.Throws(() => (ClassWith3Constructors)Invoke(constructors[2], new object[] { 121 })); + } + + [Fact] + public void Invoke_ParameterWrongType_ThrowsArgumentException() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + AssertExtensions.Throws(null, () => (ClassWith3Constructors)Invoke(constructors[1], new object[] { "hello" })); + } + + [Fact] + public void Invoke_ExistingInstance() + { + // Should not produce a second object. + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + ClassWith3Constructors obj1 = new ClassWith3Constructors(100, "hello"); + ClassWith3Constructors obj2 = (ClassWith3Constructors)Invoke(constructors[2], obj1, new object[] { 999, "initialized" }); + Assert.Null(obj2); + Assert.Equal(999, obj1.intValue); + Assert.Equal("initialized", obj1.stringValue); + } + + [Fact] + public void Invoke_NullForObj() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); + Assert.Throws(() => Invoke(constructors[2], obj: null, new object[] { 999, "initialized" })); + } + + [Fact] + [ActiveIssue("https://github.com/mono/mono/issues/15026", TestRuntimes.Mono)] + public void Invoke_AbstractClass_ThrowsMemberAccessException() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoAbstractBase)); + Assert.Throws(() => (ConstructorInfoAbstractBase)Invoke(constructors[0], new object[0])); + } + + [Fact] + public void Invoke_SubClass() + { + ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoDerived)); + ConstructorInfoDerived obj = null; + obj = (ConstructorInfoDerived)Invoke(constructors[0], new object[] { }); + Assert.NotNull(obj); + } + + [Fact] + public void Invoke_Struct() + { + ConstructorInfo[] constructors = GetConstructors(typeof(StructWith1Constructor)); + StructWith1Constructor obj; + obj = (StructWith1Constructor)Invoke(constructors[0], new object[] { 1, 2 }); + Assert.Equal(1, obj.x); + Assert.Equal(2, obj.y); + } + } +} diff --git a/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs b/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs index 34d04906a8055b..37498347ac48fe 100644 --- a/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs +++ b/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs @@ -2,15 +2,29 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Linq; using Xunit; #pragma warning disable 0414 namespace System.Reflection.Tests { - public class ConstructorInfoTests + /// + /// These tests use the shared tests from the base class with ConstructorInfo.Invoke. + /// + public sealed class ConstructorInfoTests : ConstructorCommonTests { + public override object Invoke(ConstructorInfo constructorInfo, object?[]? parameters) + { + return constructorInfo.Invoke(parameters); + } + + public override object? Invoke(ConstructorInfo constructorInfo, object obj, object?[]? parameters) + { + return constructorInfo.Invoke(obj, parameters); + } + + protected override bool IsExceptionWrapped => true; + [Fact] public void ConstructorName() { @@ -50,15 +64,6 @@ public void GetHashCodeTest() } } - [Fact] - public void Invoke() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - Assert.Equal(3, constructors.Length); - ClassWith3Constructors obj = (ClassWith3Constructors)constructors[0].Invoke(null); - Assert.NotNull(obj); - } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsInvokingStaticConstructorsSupported))] public void Invoke_StaticConstructor_NullObject_NullParameters() { @@ -88,44 +93,6 @@ public void Invoke_StaticConstructorMultipleTimes() Assert.Equal(1, ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection.VisibleStatics.s_cctorCallCount); } - [Fact] - [ActiveIssue("https://github.com/mono/mono/issues/15024", TestRuntimes.Mono)] - public void Invoke_StaticConstructor_ThrowsMemberAccessException() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWithStaticConstructor)); - Assert.Equal(1, constructors.Length); - Assert.Throws(() => constructors[0].Invoke(new object[0])); - } - - [Fact] - public void Invoke_OneDimensionalArray() - { - ConstructorInfo[] constructors = GetConstructors(typeof(object[])); - int[] arraylength = { 1, 2, 99, 65535 }; - - // Try to invoke Array ctors with different lengths - foreach (int length in arraylength) - { - // Create big Array with elements - object[] arr = (object[])constructors[0].Invoke(new object[] { length }); - Assert.Equal(arr.Length, length); - } - } - - [Fact] - public void Invoke_OneDimensionalArray_NegativeLengths_ThrowsOverflowException() - { - ConstructorInfo[] constructors = GetConstructors(typeof(object[])); - int[] arraylength = new int[] { -1, -2, -99 }; - // Try to invoke Array ctors with different lengths - foreach (int length in arraylength) - { - // Create big Array with elements - Exception ex = Assert.Throws(() => constructors[0].Invoke(new object[] { length })); - Assert.IsType(ex.InnerException); - } - } - [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/67531", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void Invoke_TwoDimensionalArray_CustomBinder_IncorrectTypeArguments() @@ -138,23 +105,6 @@ public void Invoke_TwoDimensionalArray_CustomBinder_IncorrectTypeArguments() Assert.True(args[1] is int); } - [Fact] - public void Invoke_OneParameter() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - ClassWith3Constructors obj = (ClassWith3Constructors)constructors[1].Invoke(new object[] { 100 }); - Assert.Equal(100, obj.intValue); - } - - [Fact] - public void Invoke_TwoParameters() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - ClassWith3Constructors obj = (ClassWith3Constructors)constructors[2].Invoke(new object[] { 101, "hello" }); - Assert.Equal(101, obj.intValue); - Assert.Equal("hello", obj.stringValue); - } - [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/67531", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public void Invoke_TwoParameters_CustomBinder_IncorrectTypeArgument() @@ -169,66 +119,6 @@ public void Invoke_TwoParameters_CustomBinder_IncorrectTypeArgument() Assert.True(args[1] is string); } - [Fact] - public void Invoke_NoParameters_ThowsTargetParameterCountException() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - Assert.Throws(() => constructors[2].Invoke(new object[0])); - } - - [Fact] - public void Invoke_ParameterMismatch_ThrowsTargetParameterCountException() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - Assert.Throws(() => (ClassWith3Constructors)constructors[2].Invoke(new object[] { 121 })); - } - - [Fact] - public void Invoke_ParameterWrongType_ThrowsArgumentException() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - AssertExtensions.Throws(null, () => (ClassWith3Constructors)constructors[1].Invoke(new object[] { "hello" })); - } - - [Fact] - public void Invoke_ExistingInstance() - { - // Should not produce a second object. - ConstructorInfo[] constructors = GetConstructors(typeof(ClassWith3Constructors)); - ClassWith3Constructors obj1 = new ClassWith3Constructors(100, "hello"); - ClassWith3Constructors obj2 = (ClassWith3Constructors)constructors[2].Invoke(obj1, new object[] { 999, "initialized" }); - Assert.Null(obj2); - Assert.Equal(999, obj1.intValue); - Assert.Equal("initialized", obj1.stringValue); - } - - [Fact] - [ActiveIssue("https://github.com/mono/mono/issues/15026", TestRuntimes.Mono)] - public void Invoke_AbstractClass_ThrowsMemberAccessException() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoAbstractBase)); - Assert.Throws(() => (ConstructorInfoAbstractBase)constructors[0].Invoke(new object[0])); - } - - [Fact] - public void Invoke_SubClass() - { - ConstructorInfo[] constructors = GetConstructors(typeof(ConstructorInfoDerived)); - ConstructorInfoDerived obj = null; - obj = (ConstructorInfoDerived)constructors[0].Invoke(new object[] { }); - Assert.NotNull(obj); - } - - [Fact] - public void Invoke_Struct() - { - ConstructorInfo[] constructors = GetConstructors(typeof(StructWith1Constructor)); - StructWith1Constructor obj; - obj = (StructWith1Constructor)constructors[0].Invoke(new object[] { 1, 2 }); - Assert.Equal(1, obj.x); - Assert.Equal(2, obj.y); - } - [Fact] public void IsConstructor_ReturnsTrue() { @@ -243,9 +133,18 @@ public void IsPublic() Assert.True(constructors[0].IsPublic); } - public static ConstructorInfo[] GetConstructors(Type type) + // Use this class only from the Invoke_StaticConstructorMultipleTimes method + public static class ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection { - return type.GetTypeInfo().DeclaredConstructors.ToArray(); + public static class VisibleStatics + { + public static int s_cctorCallCount; + } + + static ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection() + { + VisibleStatics.s_cctorCallCount++; + } } } @@ -281,20 +180,6 @@ public static class ClassWithStaticConstructor static ClassWithStaticConstructor() { } } - // Use this class only from the Invoke_StaticConstructorMultipleTimes method - public static class ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection - { - public static class VisibleStatics - { - public static int s_cctorCallCount; - } - - static ClassWithStaticConstructorThatIsCalledMultipleTimesViaReflection() - { - VisibleStatics.s_cctorCallCount++; - } - } - public struct StructWith1Constructor { public int x; diff --git a/src/libraries/System.Reflection/tests/ConstructorInvokerTests.cs b/src/libraries/System.Reflection/tests/ConstructorInvokerTests.cs index 86fa1c4012c270..f5313bde579844 100644 --- a/src/libraries/System.Reflection/tests/ConstructorInvokerTests.cs +++ b/src/libraries/System.Reflection/tests/ConstructorInvokerTests.cs @@ -1,13 +1,26 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Runtime.CompilerServices; using Xunit; namespace System.Reflection.Tests { - public class ConstructorInvokerTests + /// + /// These tests use the shared tests from the base class with ConstructorInvoker.Invoke. + /// + public sealed class ConstructorInvokerTests : ConstructorCommonTests { + public override object Invoke(ConstructorInfo constructorInfo, object?[]? parameters) + { + return ConstructorInvoker.Create(constructorInfo).Invoke(new Span(parameters)); + } + + public override object? Invoke(ConstructorInfo constructorInfo, object obj, object?[]? parameters) + { + return MethodInvoker.Create(constructorInfo).Invoke(obj, new Span(parameters)); + } + + protected override bool IsExceptionWrapped => false; [Fact] public void Args_0() @@ -162,16 +175,13 @@ public void ThrowsNonWrappedException_5() } [Fact] - public void ExistingInstance() + public void Invoke_StaticConstructor_NullObject_NullParameters() { - ConstructorInfo ci = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes); - TestClass tc = (TestClass)RuntimeHelpers.GetUninitializedObject(typeof(TestClass)); - Assert.Null(tc._args); + ConstructorInfo[] constructors = GetConstructors(typeof(ClassWithStaticConstructor)); + Assert.Equal(1, constructors.Length); - MethodInvoker invoker = MethodInvoker.Create(ci); - object? obj = invoker.Invoke(tc); - Assert.Equal("0", tc._args); - Assert.Null(obj); + // Invoker classes do not support calling class constructors; use standard reflection for that. + Assert.Throws(() => Invoke(constructors[0], null, new object[] { })); } private class TestClass diff --git a/src/libraries/System.Reflection/tests/InvokeEmit/System.Reflection.InvokeEmit.Tests.csproj b/src/libraries/System.Reflection/tests/InvokeEmit/System.Reflection.InvokeEmit.Tests.csproj index 7b1e61038ccb5d..757b631140f2d6 100644 --- a/src/libraries/System.Reflection/tests/InvokeEmit/System.Reflection.InvokeEmit.Tests.csproj +++ b/src/libraries/System.Reflection/tests/InvokeEmit/System.Reflection.InvokeEmit.Tests.csproj @@ -7,8 +7,12 @@ + + + + diff --git a/src/libraries/System.Reflection/tests/InvokeInterpreted/System.Reflection.InvokeInterpreted.Tests.csproj b/src/libraries/System.Reflection/tests/InvokeInterpreted/System.Reflection.InvokeInterpreted.Tests.csproj index 64dc87d71c0864..5d71379e2d5ca9 100644 --- a/src/libraries/System.Reflection/tests/InvokeInterpreted/System.Reflection.InvokeInterpreted.Tests.csproj +++ b/src/libraries/System.Reflection/tests/InvokeInterpreted/System.Reflection.InvokeInterpreted.Tests.csproj @@ -7,8 +7,12 @@ + + + + diff --git a/src/libraries/System.Reflection/tests/MethodCommonTests.cs b/src/libraries/System.Reflection/tests/MethodCommonTests.cs new file mode 100644 index 00000000000000..b2e8e2f84fbc27 --- /dev/null +++ b/src/libraries/System.Reflection/tests/MethodCommonTests.cs @@ -0,0 +1,297 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using Xunit; + +namespace System.Reflection.Tests +{ + /// + /// These tests are shared with MethodInfo.Invoke and MethodInvoker.Invoke by using + /// the abstract Invoke(...) method below. + /// + public abstract class MethodCommonTests + { + public abstract object? Invoke(MethodInfo methodInfo, object? obj, object?[]? parameters); + + protected abstract bool SupportsMissing { get; } + + protected static MethodInfo GetMethod(Type type, string name) + { + return type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).First(method => method.Name.Equals(name)); + } + + [Fact] + public void InvokeNullableRefs() + { + object?[] args; + + int? iNull = null; + args = new object[] { iNull }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.Null)), null, args)); + Assert.Null(args[0]); + Assert.False(((int?)args[0]).HasValue); + + args = new object[] { iNull }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullBoxed)), null, args)); + Assert.Null(args[0]); + + args = new object[] { iNull, 10 }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValue)), null, args)); + Assert.IsType(args[0]); + Assert.Equal(10, (int)args[0]); + + iNull = 42; + args = new object[] { iNull, 42 }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.ValueToNull)), null, args)); + Assert.Null(args[0]); + + iNull = null; + args = new object[] { iNull, 10 }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValueBoxed)), null, args)); + Assert.IsType(args[0]); + Assert.Equal(10, (int)args[0]); + + static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod( + name, BindingFlags.Public | BindingFlags.Static)!; + } + + [Fact] + public void InvokeBoxedNullableRefs() + { + object?[] args; + + object? iNull = null; + args = new object[] { iNull }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.Null)), null, args)); + Assert.Null(args[0]); + + args = new object[] { iNull }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullBoxed)), null, args)); + Assert.Null(args[0]); + + args = new object[] { iNull, 10 }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValue)), null, args)); + Assert.IsType(args[0]); + Assert.Equal(10, (int)args[0]); + + iNull = 42; + args = new object[] { iNull, 42 }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.ValueToNull)), null, args)); + Assert.Null(args[0]); + + iNull = null; + args = new object[] { iNull, 10 }; + Assert.True((bool)Invoke(GetMethod(nameof(NullableRefMethods.NullToValueBoxed)), null, args)); + Assert.IsType(args[0]); + Assert.Equal(10, (int)args[0]); + + static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod( + name, BindingFlags.Public | BindingFlags.Static)!; + } + + [Fact] + public void InvokeEnum() + { + // Enums only need to match by primitive type. + Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)). + Invoke(null, new object[] { OtherColorsInt.Red })); + + // Widening allowed + Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)). + Invoke(null, new object[] { ColorsShort.Red })); + + // Narrowing not allowed + Assert.Throws(() => GetMethod(nameof(EnumMethods.PassColorsShort)). + Invoke(null, new object[] { OtherColorsInt.Red })); + + static MethodInfo GetMethod(string name) => typeof(EnumMethods).GetMethod( + name, BindingFlags.Public | BindingFlags.Static)!; + } + + [Fact] + public void InvokeNullableEnumParameterDefaultNo() + { + MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNo", BindingFlags.Static | BindingFlags.NonPublic); + + Assert.Null(Invoke(method, null, new object?[] { default(object) })); + Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { YesNo.No })); + Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { YesNo.Yes })); + + if (SupportsMissing) + { + Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { Type.Missing })); + } + } + + [Fact] + public void InvokeNullableEnumParameterDefaultYes() + { + MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic); + + Assert.Null(Invoke(method, null, new object?[] { default(object) })); + Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { YesNo.No })); + Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { YesNo.Yes })); + + if (SupportsMissing) + { + Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { Type.Missing })); + } + } + + [Fact] + public void InvokeNonNullableEnumParameterDefaultYes() + { + MethodInfo method = typeof(EnumMethods).GetMethod("NonNullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic); + + Assert.Equal(YesNo.No, Invoke(method, null, new object[] { default(object) })); + Assert.Equal(YesNo.No, Invoke(method, null, new object[] { YesNo.No })); + Assert.Equal(YesNo.Yes, Invoke(method, null, new object[] { YesNo.Yes })); + + if (SupportsMissing) + { + Assert.Equal(YesNo.Yes, Invoke(method, null, new object[] { Type.Missing })); + } + } + + [Fact] + public void InvokeNullableEnumParameterDefaultNull() + { + MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNull", BindingFlags.Static | BindingFlags.NonPublic); + + Assert.Null(Invoke(method, null, new object?[] { default(object) })); + Assert.Equal(YesNo.No, Invoke(method, null, new object?[] { YesNo.No })); + Assert.Equal(YesNo.Yes, Invoke(method, null, new object?[] { YesNo.Yes })); + + if (SupportsMissing) + { + Assert.Null(Invoke(method, null, new object?[] { Type.Missing })); + } + } + + [Fact] + public void ValueTypeMembers_WithOverrides() + { + ValueTypeWithOverrides obj = new() { Id = 1 }; + + // ToString is overridden. + Assert.Equal("Hello", (string)Invoke(GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.ToString)), + obj, null)); + + // Ensure a normal method works. + Assert.Equal(1, (int)Invoke(GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.GetId)), + obj, null)); + } + + [Fact] + public void ValueTypeMembers_WithoutOverrides() + { + ValueTypeWithoutOverrides obj = new() { Id = 1 }; + + // ToString is not overridden. + Assert.Equal(typeof(ValueTypeWithoutOverrides).ToString(), (string) Invoke(GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.ToString)), + obj, null)); + + // Ensure a normal method works. + Assert.Equal(1, (int)Invoke(GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.GetId)), + obj, null)); + } + + [Fact] + public void NullableOfTMembers() + { + // Ensure calling a method on Nullable works. + MethodInfo mi = GetMethod(typeof(int?), nameof(Nullable.GetValueOrDefault)); + Assert.Equal(42, Invoke(mi, 42, null)); + } + + [Fact] + public void CopyBackWithByRefArgs() + { + object i = 42; + object[] args = new object[] { i }; + Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByRef)), null, args); + Assert.Equal(43, (int)args[0]); + Assert.NotSame(i, args[0]); // A copy should be made; a boxed instance should never be directly updated. + + i = 42; + args = new object[] { i }; + Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByNullableRef)), null, args); + Assert.Equal(43, (int)args[0]); + Assert.NotSame(i, args[0]); + + object o = null; + args = new object[] { o }; + Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNonNullByRef)), null, args); + Assert.NotNull(args[0]); + + o = new object(); + args = new object[] { o }; + Invoke(GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNullByRef)), null, args); + Assert.Null(args[0]); + } + + [Fact] + public unsafe void TestFunctionPointerDirect() + { + // Sanity checks for direct invocation. + void* fn = FunctionPointerMethods.GetFunctionPointer(); + Assert.True(FunctionPointerMethods.GetFunctionPointer()(42)); + Assert.True(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 42)); + Assert.True(FunctionPointerMethods.CallFcnPtr_Void(fn, 42)); + Assert.False(FunctionPointerMethods.GetFunctionPointer()(41)); + Assert.False(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 41)); + Assert.False(FunctionPointerMethods.CallFcnPtr_Void(fn, 41)); + } + + [Fact] + public unsafe void TestFunctionPointerAsIntPtrArgType() + { + void* fn = FunctionPointerMethods.GetFunctionPointer(); + + MethodInfo m; + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_IntPtr)); + Assert.True((bool)Invoke(m, null, new object[] { (IntPtr)fn, 42 })); + Assert.False((bool)Invoke(m, null, new object[] { (IntPtr)fn, 41 })); + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void)); + Assert.True((bool)Invoke(m, null, new object[] { (IntPtr)fn, 42 })); + Assert.False((bool)Invoke(m, null, new object[] { (IntPtr)fn, 41 })); + } + + [Fact] + public unsafe void TestFunctionPointerAsUIntPtrArgType() + { + void* fn = FunctionPointerMethods.GetFunctionPointer(); + + MethodInfo m; + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_UIntPtr)); + Assert.True((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 42 })); + Assert.False((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 41 })); + + m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void)); + Assert.True((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 42 })); + Assert.False((bool)Invoke(m, null, new object[] { (UIntPtr)fn, 41 })); + } + + [Fact] + public unsafe void TestFunctionPointerAsArgType() + { + void* fn = FunctionPointerMethods.GetFunctionPointer(); + MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_FP)); + Assert.True((bool)Invoke(m, null, new object[] { (IntPtr)fn, 42 })); + Assert.False((bool)Invoke(m, null, new object[] { (IntPtr)fn, 41 })); + } + + [Fact] + public unsafe void TestFunctionPointerAsReturnType() + { + MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.GetFunctionPointer)); + object ret = Invoke(m, null, null); + Assert.IsType(ret); + Assert.True((IntPtr)ret != 0); + } + } +} diff --git a/src/libraries/System.Reflection/tests/MethodInfoTests.cs b/src/libraries/System.Reflection/tests/MethodInfoTests.cs index 769fc94266a083..341fb7fcb9de11 100644 --- a/src/libraries/System.Reflection/tests/MethodInfoTests.cs +++ b/src/libraries/System.Reflection/tests/MethodInfoTests.cs @@ -6,12 +6,21 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Xunit; -using Xunit.Sdk; namespace System.Reflection.Tests { - public class MethodInfoTests + /// + /// These tests use the shared tests from the base class with MethodInfo.Invoke. + /// + public sealed class MethodInfoTests : MethodCommonTests { + public override object? Invoke(MethodInfo methodInfo, object? obj, object?[]? parameters) + { + return methodInfo.Invoke(obj, parameters); + } + + protected override bool SupportsMissing => false; + [Fact] public void CreateDelegate_PublicMethod() { @@ -361,7 +370,7 @@ public static IEnumerable Invoke_TestData() [Theory] [MemberData(nameof(Invoke_TestData))] - public void Invoke(Type methodDeclaringType, string methodName, object obj, object[] parameters, object result) + public void InvokeWithTestData(Type methodDeclaringType, string methodName, object obj, object[] parameters, object result) { MethodInfo method = GetMethod(methodDeclaringType, methodName); Assert.Equal(result, method.Invoke(obj, parameters)); @@ -370,8 +379,8 @@ public void Invoke(Type methodDeclaringType, string methodName, object obj, obje [Fact] public void Invoke_ParameterSpecification_ArrayOfMissing() { - Invoke(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new object[] { Type.Missing }, Type.Missing); - Invoke(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new Missing[] { Missing.Value }, Missing.Value); + InvokeWithTestData(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new object[] { Type.Missing }, Type.Missing); + InvokeWithTestData(typeof(MethodInfoDefaultParameters), "OptionalObjectParameter", new MethodInfoDefaultParameters(), new Missing[] { Missing.Value }, Missing.Value); } [Fact] @@ -620,149 +629,6 @@ public void ToStringTest_ByMethodInfo(MethodInfo methodInfo, string expected) Assert.Equal(expected, methodInfo.ToString()); } - [Fact] - public void InvokeNullableRefs() - { - object?[] args; - - int? iNull = null; - args = new object[] { iNull }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.Null)).Invoke(null, args)); - Assert.Null(args[0]); - Assert.False(((int?)args[0]).HasValue); - - args = new object[] { iNull }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullBoxed)).Invoke(null, args)); - Assert.Null(args[0]); - - args = new object[] { iNull, 10 }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValue)).Invoke(null, args)); - Assert.IsType(args[0]); - Assert.Equal(10, (int)args[0]); - - iNull = 42; - args = new object[] { iNull, 42 }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.ValueToNull)).Invoke(null, args)); - Assert.Null(args[0]); - - iNull = null; - args = new object[] { iNull, 10 }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValueBoxed)).Invoke(null, args)); - Assert.IsType(args[0]); - Assert.Equal(10, (int)args[0]); - - static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod( - name, BindingFlags.Public | BindingFlags.Static)!; - } - - [Fact] - public void InvokeBoxedNullableRefs() - { - object?[] args; - - object? iNull = null; - args = new object[] { iNull }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.Null)).Invoke(null, args)); - Assert.Null(args[0]); - - args = new object[] { iNull }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullBoxed)).Invoke(null, args)); - Assert.Null(args[0]); - - args = new object[] { iNull, 10 }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValue)).Invoke(null, args)); - Assert.IsType(args[0]); - Assert.Equal(10, (int)args[0]); - - iNull = 42; - args = new object[] { iNull, 42 }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.ValueToNull)).Invoke(null, args)); - Assert.Null(args[0]); - - iNull = null; - args = new object[] { iNull, 10 }; - Assert.True((bool)GetMethod(nameof(NullableRefMethods.NullToValueBoxed)).Invoke(null, args)); - Assert.IsType(args[0]); - Assert.Equal(10, (int)args[0]); - - static MethodInfo GetMethod(string name) => typeof(NullableRefMethods).GetMethod( - name, BindingFlags.Public | BindingFlags.Static)!; - } - - [Fact] - public void InvokeEnum() - { - // Enums only need to match by primitive type. - Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)). - Invoke(null, new object[] { OtherColorsInt.Red })); - - // Widening allowed - Assert.True((bool)GetMethod(nameof(EnumMethods.PassColorsInt)). - Invoke(null, new object[] { ColorsShort.Red })); - - // Narrowing not allowed - Assert.Throws(() => GetMethod(nameof(EnumMethods.PassColorsShort)). - Invoke(null, new object[] { OtherColorsInt.Red })); - - static MethodInfo GetMethod(string name) => typeof(EnumMethods).GetMethod( - name, BindingFlags.Public | BindingFlags.Static)!; - } - - [Fact] - public static void InvokeNullableEnumParameterDefaultNo() - { - MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNo", BindingFlags.Static | BindingFlags.NonPublic); - - Assert.Null(method.Invoke(null, new object?[] { default(object) })); - Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes })); - Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { Type.Missing })); - } - - [Fact] - public static void InvokeNullableEnumParameterDefaultYes() - { - MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic); - - Assert.Null(method.Invoke(null, new object?[] { default(object) })); - Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { Type.Missing })); - } - - [Fact] - public static void InvokeNonNullableEnumParameterDefaultYes() - { - MethodInfo method = typeof(EnumMethods).GetMethod("NonNullableEnumDefaultYes", BindingFlags.Static | BindingFlags.NonPublic); - - Assert.Equal(YesNo.No, method.Invoke(null, new object[] { default(object) })); - Assert.Equal(YesNo.No, method.Invoke(null, new object[] { YesNo.No })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object[] { YesNo.Yes })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object[] { Type.Missing })); - } - - [Fact] - public static void InvokeNullableEnumParameterDefaultNull() - { - MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumDefaultNull", BindingFlags.Static | BindingFlags.NonPublic); - - Assert.Null(method.Invoke(null, new object?[] { default(object) })); - Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes })); - Assert.Null(method.Invoke(null, new object?[] { Type.Missing })); - } - - [Fact] - public static void InvokeNullableEnumParameterNoDefault() - { - MethodInfo method = typeof(EnumMethods).GetMethod("NullableEnumNoDefault", BindingFlags.Static | BindingFlags.NonPublic); - - Assert.Null(method.Invoke(null, new object?[] { default(object) })); - Assert.Equal(YesNo.No, method.Invoke(null, new object?[] { YesNo.No })); - Assert.Equal(YesNo.Yes, method.Invoke(null, new object?[] { YesNo.Yes })); - Assert.Throws(() => method.Invoke(null, new object?[] { Type.Missing })); - } - public static IEnumerable MethodNameAndArguments() { yield return new object[] { nameof(Sample.DefaultString), "Hello", "Hi" }; @@ -805,68 +671,6 @@ public static void InvokeCopiesBackMissingParameterAndArgument() Assert.Null(args[0]); } - [Fact] - public void ValueTypeMembers_WithOverrides() - { - ValueTypeWithOverrides obj = new() { Id = 1 }; - - // ToString is overridden. - Assert.Equal("Hello", (string)GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.ToString)). - Invoke(obj, null)); - - // Ensure a normal method works. - Assert.Equal(1, (int)GetMethod(typeof(ValueTypeWithOverrides), nameof(ValueTypeWithOverrides.GetId)). - Invoke(obj, null)); - } - - [Fact] - public void ValueTypeMembers_WithoutOverrides() - { - ValueTypeWithoutOverrides obj = new() { Id = 1 }; - - // ToString is not overridden. - Assert.Equal(typeof(ValueTypeWithoutOverrides).ToString(), (string)GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.ToString)). - Invoke(obj, null)); - - // Ensure a normal method works. - Assert.Equal(1, (int)GetMethod(typeof(ValueTypeWithoutOverrides), nameof(ValueTypeWithoutOverrides.GetId)). - Invoke(obj, null)); - } - - [Fact] - public void NullableOfTMembers() - { - // Ensure calling a method on Nullable works. - MethodInfo mi = GetMethod(typeof(int?), nameof(Nullable.GetValueOrDefault)); - Assert.Equal(42, mi.Invoke(42, null)); - } - - [Fact] - public void CopyBackWithByRefArgs() - { - object i = 42; - object[] args = new object[] { i }; - GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByRef)).Invoke(null, args); - Assert.Equal(43, (int)args[0]); - Assert.NotSame(i, args[0]); // A copy should be made; a boxed instance should never be directly updated. - - i = 42; - args = new object[] { i }; - GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.IncrementByNullableRef)).Invoke(null, args); - Assert.Equal(43, (int)args[0]); - Assert.NotSame(i, args[0]); - - object o = null; - args = new object[] { o }; - GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNonNullByRef)).Invoke(null, args); - Assert.NotNull(args[0]); - - o = new object(); - args = new object[] { o }; - GetMethod(typeof(CopyBackMethods), nameof(CopyBackMethods.SetToNullByRef)).Invoke(null, args); - Assert.Null(args[0]); - } - [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsMonoInterpreter))] [ActiveIssue("https://github.com/dotnet/runtime/issues/69919", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] @@ -894,69 +698,6 @@ private static void SecondCall(MethodInfo mi) Assert.Contains("TestAssembly", asm.ToString()); } - [Fact] - private static unsafe void TestFunctionPointerDirect() - { - // Sanity checks for direct invocation. - void* fn = FunctionPointerMethods.GetFunctionPointer(); - Assert.True(FunctionPointerMethods.GetFunctionPointer()(42)); - Assert.True(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 42)); - Assert.True(FunctionPointerMethods.CallFcnPtr_Void(fn, 42)); - Assert.False(FunctionPointerMethods.GetFunctionPointer()(41)); - Assert.False(FunctionPointerMethods.CallFcnPtr_IntPtr((IntPtr)fn, 41)); - Assert.False(FunctionPointerMethods.CallFcnPtr_Void(fn, 41)); - } - - [Fact] - private static unsafe void TestFunctionPointerAsIntPtrArgType() - { - void* fn = FunctionPointerMethods.GetFunctionPointer(); - - MethodInfo m; - - m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_IntPtr)); - Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 })); - Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 })); - - m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void)); - Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 })); - Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 })); - } - - [Fact] - private static unsafe void TestFunctionPointerAsUIntPtrArgType() - { - void* fn = FunctionPointerMethods.GetFunctionPointer(); - - MethodInfo m; - - m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_UIntPtr)); - Assert.True((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 42 })); - Assert.False((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 41 })); - - m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_Void)); - Assert.True((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 42 })); - Assert.False((bool)m.Invoke(null, new object[] { (UIntPtr)fn, 41 })); - } - - [Fact] - private static unsafe void TestFunctionPointerAsArgType() - { - void* fn = FunctionPointerMethods.GetFunctionPointer(); - MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.CallFcnPtr_FP)); - Assert.True((bool)m.Invoke(null, new object[] { (IntPtr)fn, 42 })); - Assert.False((bool)m.Invoke(null, new object[] { (IntPtr)fn, 41 })); - } - - [Fact] - private static unsafe void TestFunctionPointerAsReturnType() - { - MethodInfo m = GetMethod(typeof(FunctionPointerMethods), nameof(FunctionPointerMethods.GetFunctionPointer)); - object ret = m.Invoke(null, null); - Assert.IsType(ret); - Assert.True((IntPtr)ret != 0); - } - //Methods for Reflection Metadata private void DummyMethod1(string str, int iValue, long lValue) { @@ -965,11 +706,6 @@ private void DummyMethod1(string str, int iValue, long lValue) private void DummyMethod2() { } - - private static MethodInfo GetMethod(Type type, string name) - { - return type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).First(method => method.Name.Equals(name)); - } } #pragma warning disable 0414 diff --git a/src/libraries/System.Reflection/tests/MethodInvokerTests.cs b/src/libraries/System.Reflection/tests/MethodInvokerTests.cs index 97c9865a64fdaf..94d701507eac1d 100644 --- a/src/libraries/System.Reflection/tests/MethodInvokerTests.cs +++ b/src/libraries/System.Reflection/tests/MethodInvokerTests.cs @@ -2,13 +2,22 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Linq; using Xunit; namespace System.Reflection.Tests { - public class MethodInvokerTests + /// + /// These tests use the shared tests from the base class with MethodInvoker.Invoke. + /// + public class MethodInvokerTests : MethodCommonTests { + public override object? Invoke(MethodInfo methodInfo, object? obj, object?[]? parameters) + { + return MethodInvoker.Create(methodInfo).Invoke(obj, new Span(parameters)); + } + + protected override bool SupportsMissing => false; + [Fact] public void NullTypeValidation() { @@ -286,11 +295,6 @@ public void VerifyThisObj_Null() Assert.Throws(() => invoker.Invoke(obj: null)); } - private static MethodInfo GetMethod(Type type, string name) - { - return type.GetTypeInfo().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).First(method => method.Name.Equals(name)); - } - public static IEnumerable Invoke_TestData() => MethodInfoTests.Invoke_TestData(); private class TestClass diff --git a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj index e6adafcbaac1d5..9553a7dacc4828 100644 --- a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj +++ b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj @@ -14,14 +14,12 @@ - - - + + + + @@ -31,6 +29,7 @@ + @@ -42,8 +41,7 @@ - + From 2d5b3b3727d1cbec30a31643f8f0335e7a3c3a4d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:10:54 -0700 Subject: [PATCH 079/345] JIT: Skip Create(ToScalar(Dot(...))) transformation on mismatched types (#91089) Fix #91062 Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/morph.cpp | 6 +++++ .../JitBlue/Runtime_91062/Runtime_91062.cs | 22 +++++++++++++++++++ .../Runtime_91062/Runtime_91062.csproj | 8 +++++++ 3 files changed, 36 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.csproj diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index f29d6a57148136..52454b0c8b7316 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -10770,6 +10770,12 @@ GenTree* Compiler::fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node) break; } + // Must be working with the same types of vectors. + if (hwop1->TypeGet() != node->TypeGet()) + { + break; + } + if (toScalar != nullptr) { DEBUG_DESTROY_NODE(toScalar); diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs new file mode 100644 index 00000000000000..8886bd2044ab04 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license.aa + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Numerics; +using Xunit; + +public class Runtime_91062 +{ + [Fact] + public static void TestEntryPoint() + { + Foo(default, default); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Vector2 Foo(Vector128 v1, Vector128 v2) + { + return Vector2.Lerp(default, default, Vector128.Dot(v1, v2)); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From d379e3a1fe89d463ae55b86525fbd7713e983d9e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 15:11:09 -0700 Subject: [PATCH 080/345] Use RuntimeIdentifierGraphPath if available in runtime copy of Microsoft.NET.CrossGen.targets (#91090) Co-authored-by: Elinor Fung --- src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets b/src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets index a2912cc0822849..c539d330e8add8 100644 --- a/src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets +++ b/src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets @@ -443,7 +443,7 @@ Copyright (c) .NET Foundation. All rights reserved. Date: Fri, 25 Aug 2023 15:17:09 -0700 Subject: [PATCH 081/345] [release/8.0] Update dependencies from dotnet/roslyn (#91093) * Update dependencies from https://github.com/dotnet/roslyn build 20230824.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-2.23424.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230824.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-2.23424.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230824.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-1.23424.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230824.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-2.23424.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230824.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-2.23424.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230824.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-2.23424.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230824.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23423.10 -> To Version 4.8.0-2.23424.9 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e487aa87355a5c..90f5ad8cb33409 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - d83f0cc401672efe5afd5e9db4be43e9e06c5935 + d7e010bbe5b1d37837417fc5e79ecb2fd9b7b487 - + https://github.com/dotnet/roslyn - d83f0cc401672efe5afd5e9db4be43e9e06c5935 + d7e010bbe5b1d37837417fc5e79ecb2fd9b7b487 - + https://github.com/dotnet/roslyn - d83f0cc401672efe5afd5e9db4be43e9e06c5935 + d7e010bbe5b1d37837417fc5e79ecb2fd9b7b487 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 931464d372cb3c..e6526116aa3a83 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-2.23423.10 - 4.8.0-2.23423.10 - 4.8.0-2.23423.10 + 4.8.0-2.23424.9 + 4.8.0-2.23424.9 + 4.8.0-2.23424.9 + true True diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91056/Runtime_91056.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91056/Runtime_91056.cs new file mode 100644 index 00000000000000..a0c78804a7ee52 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91056/Runtime_91056.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; +using System.Runtime.CompilerServices; + +public class Runtime_91056 +{ + [Fact] + public static void TestEntryPoint() + { + S s = default; + if (False()) + { + s.A = 1234; + } + + Foo(0, 0, s, s); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool False() => false; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Foo(int a, int b, S s1, S s2) + { + } + + public struct S + { + public int A; + } +} \ No newline at end of file diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91056/Runtime_91056.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91056/Runtime_91056.csproj new file mode 100644 index 00000000000000..444d119c04fe97 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91056/Runtime_91056.csproj @@ -0,0 +1,12 @@ + + + + true + True + + + + + + + \ No newline at end of file From ab22bc767e5a8cc7cfba3e529cb96d968082518b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 17:15:41 -0700 Subject: [PATCH 085/345] [release/8.0] Update dependencies from dotnet/roslyn-analyzers dotnet/source-build-reference-packages (#91114) * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230824.2 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23423.2 -> To Version 3.11.0-beta1.23424.2 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230824.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23421.1 -> To Version 8.0.0-alpha.1.23424.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 90f5ad8cb33409..47f9d1ce3af669 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -95,9 +95,9 @@ 66dbaefff04250dc72849f0172e0c53bcfb3ab38 - + https://github.com/dotnet/source-build-reference-packages - f4903e46459e0348e3793055dd8b68b8b0264034 + 93c23409e630c4f267234540b0e3557b76a53ef4 @@ -371,13 +371,13 @@ https://github.com/dotnet/roslyn d7e010bbe5b1d37837417fc5e79ecb2fd9b7b487 - + https://github.com/dotnet/roslyn-analyzers - 76d99c5f3e11f0600fae074270c0d89042c360f0 + e1da9c89ca09a43ebac06a5e9ef0798407bc555b - + https://github.com/dotnet/roslyn-analyzers - 76d99c5f3e11f0600fae074270c0d89042c360f0 + e1da9c89ca09a43ebac06a5e9ef0798407bc555b https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index e6526116aa3a83..b8994b05237157 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.23423.2 - 8.0.0-preview.23423.2 + 3.11.0-beta1.23424.2 + 8.0.0-preview.23424.2 - 4.8.0-2.23424.9 - 4.8.0-2.23424.9 - 4.8.0-2.23424.9 + 4.8.0-2.23426.1 + 4.8.0-2.23426.1 + 4.8.0-2.23426.1 diff --git a/eng/Versions.props b/eng/Versions.props index 72896a31452521..f49e17b28a4a34 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23362.5 - 1.0.0-prerelease.23362.5 - 1.0.0-prerelease.23362.5 - 1.0.0-prerelease.23362.5 - 1.0.0-prerelease.23362.5 - 1.0.0-prerelease.23362.5 + 1.0.0-prerelease.23427.2 + 1.0.0-prerelease.23427.2 + 1.0.0-prerelease.23427.2 + 1.0.0-prerelease.23427.2 + 1.0.0-prerelease.23427.2 + 1.0.0-prerelease.23427.2 16.11.27-beta1.23180.1 2.0.0-beta4.23307.1 From 77f36e7f609bcafc8f312959b8a5d851a5b13d8a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 12:06:08 -0600 Subject: [PATCH 094/345] Enable System.IO.Hashing tests on ios and disable tvos (#91195) Co-authored-by: Ivan Povazan --- src/libraries/tests.proj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 7ef3d7b0235ebb..a550e9cf9cc827 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -266,6 +266,7 @@ + + From 259a8a45cf6e7b907a55c489708fdcf6e36c7c94 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 14:54:57 -0600 Subject: [PATCH 095/345] [release/8.0] Update dependencies from dotnet/roslyn-analyzers dotnet/arcade (#91154) * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230825.3 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23424.2 -> To Version 3.11.0-beta1.23425.3 * Update dependencies from https://github.com/dotnet/arcade build 20230825.2 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23422.1 -> To Version 8.0.0-beta.23425.2 Dependency coherency updates Microsoft.DotNet.XliffTasks From Version 1.0.0-beta.23418.1 -> To Version 1.0.0-beta.23423.1 (parent: Microsoft.DotNet.Arcade.Sdk * Update testPackages.proj --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Viktor Hofer --- eng/Version.Details.xml | 84 ++++++++++---------- eng/Versions.props | 34 ++++---- global.json | 6 +- src/libraries/testPackages/testPackages.proj | 16 +++- 4 files changed, 76 insertions(+), 64 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 79c4d9d853825a..aad708a98fcdce 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -107,79 +107,79 @@ - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/xliff-tasks - bb654cd4736e7e8cb99f1c355ce2b8f0a686ba74 + ed9a83526483c094fb51e7000b6f816ce6cb0325 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 https://github.com/dotnet/runtime-assets @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 4d9945d230fdd8324ce16a31c7dbd74e27a0fc9b + 90c167d5c57de4a8bced566379dbd893556c94e8 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -371,13 +371,13 @@ https://github.com/dotnet/roslyn 34268d1bb9370c7b01c742303a895a99daf10d6a - + https://github.com/dotnet/roslyn-analyzers - e1da9c89ca09a43ebac06a5e9ef0798407bc555b + 546d9ed731872c72279735c55f140ab8967f5656 - + https://github.com/dotnet/roslyn-analyzers - e1da9c89ca09a43ebac06a5e9ef0798407bc555b + 546d9ed731872c72279735c55f140ab8967f5656 https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index f49e17b28a4a34..6414c8e37f55d0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.23424.2 - 8.0.0-preview.23424.2 + 3.11.0-beta1.23425.3 + 8.0.0-preview.23425.3 8.0.100-preview.7.23329.3 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 2.5.1-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 - 8.0.0-beta.23422.1 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 2.5.1-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 + 8.0.0-beta.23425.2 6.0.0-preview.1.102 diff --git a/global.json b/global.json index 95e75305ea00be..ffe9ed56766f48 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23422.1", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23422.1", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23422.1", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23425.2", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23425.2", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23425.2", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" diff --git a/src/libraries/testPackages/testPackages.proj b/src/libraries/testPackages/testPackages.proj index 6480f5fc5928bf..9d60aeb8e6e64b 100644 --- a/src/libraries/testPackages/testPackages.proj +++ b/src/libraries/testPackages/testPackages.proj @@ -63,12 +63,24 @@ - + + + + + + + + + + + + + + From 22a50ac0d6fee725c79845e5b73fce7e10363861 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 28 Aug 2023 16:01:52 -0700 Subject: [PATCH 096/345] [ComInterfaceGenerator] Recommend [In] and [Out] attributes on array parameters (#91094) (#91231) Recommend that methods with array parameters use [In] or [Out] attributes if there are none already, and the parameter is not in, ref, or out. --- docs/project/list-of-diagnostics.md | 2 +- .../DiagnosticDescriptorProvider.cs | 1 + .../GeneratorDiagnostics.cs | 11 + .../gen/Common/Resources/Strings.resx | 25 +- .../gen/Common/Resources/xlf/Strings.cs.xlf | 41 ++- .../gen/Common/Resources/xlf/Strings.de.xlf | 41 ++- .../gen/Common/Resources/xlf/Strings.es.xlf | 41 ++- .../gen/Common/Resources/xlf/Strings.fr.xlf | 39 ++- .../gen/Common/Resources/xlf/Strings.it.xlf | 39 ++- .../gen/Common/Resources/xlf/Strings.ja.xlf | 41 ++- .../gen/Common/Resources/xlf/Strings.ko.xlf | 41 ++- .../gen/Common/Resources/xlf/Strings.pl.xlf | 39 ++- .../Common/Resources/xlf/Strings.pt-BR.xlf | 41 ++- .../gen/Common/Resources/xlf/Strings.ru.xlf | 39 ++- .../gen/Common/Resources/xlf/Strings.tr.xlf | 39 ++- .../Common/Resources/xlf/Strings.zh-Hans.xlf | 41 ++- .../Common/Resources/xlf/Strings.zh-Hant.xlf | 39 ++- .../DiagnosticDescriptorProvider.cs | 1 + .../GeneratorDiagnostics.cs | 10 + .../IncrementalValuesProviderExtensions.cs | 2 +- ...ributedMarshallingModelGeneratorFactory.cs | 11 +- .../ByValueContentsMarshalKindValidator.cs | 3 +- .../ByValueMarshalKindSupportDescriptor.cs | 166 +++++----- .../Marshalling/GeneratorDiagnostic.cs | 13 + .../Marshalling/MarshallingGenerator.cs | 4 + .../StaticPinnableManagedValueMarshaller.cs | 2 +- .../ByValueContentsMarshalling.cs | 301 ++++++++++++++++++ .../CodeSnippets.cs | 60 ++++ .../ComInterfaceGenerator.Unit.Tests.csproj | 1 + .../CompileFails.cs | 294 +---------------- .../tests/Common/TestUtils.cs | 14 +- .../ByValueContentsMarshalling.cs | 135 ++++++++ .../CodeSnippets.cs | 16 + .../CompileFails.cs | 57 ---- .../Compiles.cs | 24 -- .../TestAssets/SharedTypes/SharedTypes.csproj | 2 + 36 files changed, 1160 insertions(+), 516 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 3c9a9afb9c4199..4b46d49f5813f0 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -208,7 +208,7 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL | __`SYSLIB1089`__ | _`SYSLIB1070`-`SYSLIB1089` reserved for System.Runtime.InteropServices.JavaScript.JSImportGenerator._ | | __`SYSLIB1090`__ | Invalid 'GeneratedComInterfaceAttribute' usage | | __`SYSLIB1091`__ | Method is declared in different partial declaration than the 'GeneratedComInterface' attribute. | -| __`SYSLIB1092`__ | 'GenerateComInterfaceAttribute' usage not recommended. See aka.ms/GeneratedComInterfaceUsage for recommended usage. | +| __`SYSLIB1092`__ | Usage of '[LibraryImport|GeneratedComInterface]' does not follow recommendation. See aka.ms/[LibraryImport|GeneratedComInterface]Usage for best practices. | | __`SYSLIB1093`__ | Analysis for COM interface generation has failed | | __`SYSLIB1094`__ | The base COM interface failed to generate source. Code will not be generated for this interface. | | __`SYSLIB1095`__ | Invalid 'GeneratedComClassAttribute' usage | diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs index c676f27cb9f401..fab2d39182c8b7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/DiagnosticDescriptorProvider.cs @@ -26,6 +26,7 @@ internal sealed class DiagnosticDescriptorProvider : IDiagnosticDescriptorProvid GeneratorDiagnostic.NotSupported { NotSupportedDetails: not null, TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.UnnecessaryReturnMarshallingInfo, + GeneratorDiagnostic.NotRecommended => GeneratorDiagnostics.GeneratedComInterfaceUsageDoesNotFollowBestPractices, { IsFatal: false } => null, { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.ReturnTypeNotSupported, { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupported, diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs index b213e3a9704f29..1e1849592f7ba4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs @@ -485,6 +485,17 @@ public class Ids DiagnosticSeverity.Info, isEnabledByDefault: true); + /// + public static readonly DiagnosticDescriptor GeneratedComInterfaceUsageDoesNotFollowBestPractices = + new DiagnosticDescriptor( + Ids.NotRecommendedGeneratedComInterfaceUsage, + GetResourceString(nameof(SR.ComInterfaceUsageDoesNotFollowBestPracticesTitle)), + GetResourceString(nameof(SR.ComInterfaceUsageDoesNotFollowBestPracticesMessageWithDetails)), + Category, + DiagnosticSeverity.Info, + isEnabledByDefault: true, + helpLinkUri: "aka.ms/GeneratedComInterfaceUsage"); + /// /// Report diagnostic for invalid configuration for string marshalling. /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx index ebf0170e328752..2da298e8a7b0df 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx @@ -875,7 +875,13 @@ [In] and [Out] attributes - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. @@ -889,4 +895,19 @@ This type will be treated as a struct in the native signature, not as a native HRESULT - \ No newline at end of file + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf index e1b25c7690ffa4..829de99735954b 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf @@ -147,6 +147,16 @@ Hostování .NET COM s EnableComHosting nepodporuje rozhraní s generatedComInterfaceAttribute + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Vrácená hodnota ve spravované definici se při volání nespravované metody COM převede na parametr out. Pokud má být návratovou hodnotou kód HRESULT vrácený nespravovanou metodou COM, použijte u metody [PreserveSig]. @@ -447,6 +457,11 @@ Tento typ bude v nativním podpisu považován za strukturu, nikoli za nativní HRESULT. + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Atribut [In] není podporován, pokud není použit také atribut [Out]. Blittable arrays nelze zařadit pouze jako [In]. @@ -467,6 +482,11 @@ Poskytnuté atributy „[In]“ a „[Out]“ u tohoto parametru se na tomto parametru nepodporují. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes atributy [In] a [Out] @@ -702,6 +722,16 @@ Neplatné použití atributu VirtualMethodIndexAttribute + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Typ prvku ReadOnlySpan vrácený GetManagedValuesSource musí být stejný, jako typ prvku vrácený GetManagedValuesDestination. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Atribut „[Out]“ se podporuje pouze u parametrů pole. Zvažte použití klíčových slov „out“ nebo „ref“, aby se parametr dalo měnit. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ Typ {0}určuje, že podporuje zařazování ve směru „Out“, ale neposkytuje metodu ToManaged, která vrací spravovaný typ + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. GeneratedComInterfaceAttribute a GeneratedComClassAttribute vyžadují nebezpečný kód. Projekt se musí aktualizovat na <AllowUnsafeBlocks>true</AllowUnsafeBlocks>. @@ -1276,4 +1311,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf index 1b056b0cb4118e..1f959d763c7ba7 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf @@ -147,6 +147,16 @@ Das .NET COM-Hosting mit "EnableComHosting" unterstützt keine Schnittstellen mit "GeneratedComInterfaceAttribute". + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Der Rückgabewert in der verwalteten Definition wird beim Aufrufen der nicht verwalteten COM-Methode in einen out-Parameter konvertiert. Wenn als Rückgabewert der von der nicht verwalteten COM-Methode zurückgegebene HRESULT-Code eingesetzt werden soll, verwenden Sie "[PreserveSig]" für die Methode. @@ -447,6 +457,11 @@ Dieser Typ wird als Struktur in der nativen Signatur und nicht als natives HRESULT behandelt + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Das [In]-Attribut wird nur unterstützt, wenn auch das [Out]-Attribut verwendet wird. Blittable-Arrays können nicht nur als "[In]" gemarshallt werden. @@ -467,6 +482,11 @@ Die angegebenen Attribute \"[In]\" und \"[Out]\" für diesen Parameter werden für diesen Parameter nicht unterstützt. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In]- und [Out]-Attribute @@ -702,6 +722,16 @@ Ungültige Verwendung von "VirtualMethodIndexAttribute" + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Der von \"GetManagedValuesSource\" zurückgegebene Elementtyp \"ReadOnlySpan\" muss mit dem Elementtyp identisch sein, der von \"GetManagedValuesDestination\" zurückgegeben wird. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Das [Out]-Attribut wird nur für Arrayparameter gemarshallt werden. Erwägen Sie die Verwendung der Schlüsselwörter "out" oder "ref", um den Parameter änderbar zu machen. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ Der Typ \"{0}\" gibt an, dass das Marshalling in der Out-Richtung unterstützt wird. Er stellt jedoch keine ToManaged-Methode bereit, die den verwalteten Typ zurückgibt. + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' und 'GeneratedComClassAttribute' erfordern unsicheren Code. Das Projekt muss mit '<AllowUnsafeBlocks>wahr</AllowUnsafeBlocks>' aktualisiert werden. @@ -1276,4 +1311,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf index 7d67b06c68960e..fab077ea6bac23 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf @@ -147,6 +147,16 @@ El hospedaje COM de .NET con “EnableComHosting” no admite interfaces con “GeneratedComInterfaceAttribute” + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. El valor devuelto en la definición administrada se convertirá en un parámetro “out” al llamar al método COM no administrado. Si el valor devuelto debe ser el código HRESULT devuelto por el método COM no administrado, use “[PreserveSig]” en el método. @@ -447,6 +457,11 @@ Este tipo se tratará como una estructura en la firma nativa, no como un HRESULT nativo. + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. El atributo '[In]' no se admite a menos que también se use el atributo '[Out]'. Las matrices que se pueden transferir en bloque de bits no se pueden serializar solo como '[In]'. @@ -467,6 +482,11 @@ En este parámetro, los atributos “[In]” y “[Out]” proporcionados no se admiten. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Atributos [In] y [Out] @@ -702,6 +722,16 @@ Uso de ”VirtualMethodIndexAttribute” no válido + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. El tipo de elemento del “ReadOnlySpan” devuelto por “GetManagedValuesSource” debe ser el mismo que el tipo de elemento devuelto por “GetManagedValuesDestination”. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - El atributo "[Out]" solo se admite en parámetros de matriz. Considere la posibilidad de usar palabras clave "out" o "ref" para hacer que el parámetro sea mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ El tipo “{0}” especifica que admite la serialización en la dirección “Out”, pero no proporciona un método “ToManaged” que devuelva el tipo administrado + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. "GeneratedComInterfaceAttribute" y "GeneratedComClassAttribute" requieren código no seguro. El proyecto debe actualizarse con "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>". @@ -1276,4 +1311,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index e4a153641da409..3f8638ef4ee7f8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -147,6 +147,16 @@ L'hébergement .NET COM avec 'EnableComHosting' ne prend pas en charge les interfaces avec 'GeneratedComInterfaceAttribute' + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. La valeur de retour dans la définition managée est convertie en paramètre 'out' lors de l’appel de la méthode COM non managée. Si la valeur de retour doit être le code HRESULT retourné par la méthode COM non managée, utilisez '[PreserveSig]' sur la méthode. @@ -447,6 +457,11 @@ Ce type sera traité en tant que struct dans la signature native, et non en tant que HRESULT natif + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. L’attribut '[In]' n’est pas pris en charge, sauf si l’attribut '[Out]' est également utilisé. Les tableaux blittables ne peuvent pas être marshalés en tant que « [In] » uniquement. @@ -467,6 +482,11 @@ Les attributs « [In] » et « [Out] » fournis sur ce paramètre ne sont pas pris en charge sur ce paramètre. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Attributs [In] et [Out] @@ -702,6 +722,16 @@ Utilisation de « VirtualMethodIndexAttribute » non valide + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Le type d’élément de « ReadOnlySpan » retourné par « GetManagedValuesSource » doit être identique au type d’élément retourné par « GetManagedValuesDestination ». @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - L’attribut '[Out]' est uniquement pris en charge sur les paramètres de tableau. Envisagez d’utiliser des mots clés 'out' ou 'ref' pour rendre le paramètre mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + L’attribut '[Out]' est uniquement pris en charge sur les paramètres de tableau. Envisagez d’utiliser des mots clés 'out' ou 'ref' pour rendre le paramètre mutable. @@ -917,6 +947,11 @@ Le type « {0} » spécifie qu’il prend en charge le marshaling dans la direction « Out », mais il ne fournit pas de méthode « ToManaged » qui retourne le type managé + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. « GeneratedComInterfaceAttribute » et « GeneratedComClassAttribute » nécessitent du code non sécurisé. Le projet doit être mis à jour avec « <AllowUnsafeBlocks>true</AllowUnsafeBlocks> ». diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf index acc74fc43e9ed5..d6ed0fd8fc3b35 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf @@ -147,6 +147,16 @@ L'hosting COM .NET con 'EnableComHosting' non supporta le interfacce con 'GeneratedComInterfaceAttribute'. + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Il valore restituito nella definizione gestita verrà convertito in un parametro 'out' quando si chiama il metodo COM non gestito. Se il valore restituito deve essere il codice HRESULT restituito dal metodo COM non gestito, utilizzare '[PreserveSig]' sul metodo. @@ -447,6 +457,11 @@ Questo tipo verrà considerato come uno struct nella firma nativa, non come HRESULT nativo + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. L'attributo '[In]' non è supportato a meno che non venga usato anche l'attributo '[Out]'. Le matrici copiabili da BLT non possono essere sottoposte a marshalling solo come '[In]'. @@ -467,6 +482,11 @@ Gli attributi '[In]' e '[Out]' specificati per questo parametro non sono supportati in questo parametro. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Attributi [In] e [Out] @@ -702,6 +722,16 @@ Utilizzo di 'VirtualMethodIndexAttribute' non valido + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Il tipo di elemento di 'ReadOnlySpan' restituito da 'GetManagedValuesSource' deve essere uguale al tipo di elemento restituito da 'GetManagedValuesDestination'. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - L'attributo '[Out]' è supportato solo nei parametri di matrice. Provare a usare le parole chiave 'out' o 'ref' per rendere modificabile il parametro. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + L'attributo '[Out]' è supportato solo nei parametri di matrice. Provare a usare le parole chiave 'out' o 'ref' per rendere modificabile il parametro. @@ -917,6 +947,11 @@ Il tipo '{0}' specifica che supporta il marshalling nella direzione 'Out', ma non fornisce un metodo 'ToManaged' che restituisce il tipo gestito + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. GeneratedComInterfaceAttribute e 'GeneratedComClassAttribute' richiedono codice non gestito. Il progetto deve essere aggiornato con '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf index 946718bd8962ed..0963a7a2aa5267 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf @@ -147,6 +147,16 @@ 'EnableComHosting' を使用した .NET COM ホスティングでは、'GeneratedComInterfaceAttribute' のインターフェイスはサポートされていません + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. マネージド定義の戻り値は、アンマネージド COM メソッドを呼び出すときに 'out' パラメーターに変換されます。戻り値を、アンマネージド COM メソッドによって返される HRESULT コードにする場合は、メソッドで '[PreserveSig]' を使用してください。 @@ -447,6 +457,11 @@ この型はネイティブの HRESULT ではなく、ネイティブ シグネチャの構造体として扱われます + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. '[In]'属性は、'[Out]'属性も使用しない限りサポートされません。Blittable 配列は、'[In]'としてのみマーシャリングできません。 @@ -467,6 +482,11 @@ このパラメーターに指定された '[In]' 属性と '[Out]' 属性は、このパラメーターではサポートされていません。 + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes 属性の[In]と[Out] @@ -702,6 +722,16 @@ 'VirtualMethodIndexAttribute' の使用法が無効です + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource' によって返される 'ReadOnlySpan' の要素型は、'GetManagedValuesDestination' によって返される要素型と同じである必要があります。 @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - '[Out]' 属性は、配列パラメーターでのみサポートされます。パラメーターを変更可能にするには、'out' または 'ref' キーワードを使用することを検討してください。 + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ 型 '{0}' は、'Out' 方向のマーシャリングをサポートしますが、マネージド型を返す 'ToManaged' メソッドは指定されません + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' および 'GeneratedComClassAttribute' にはアンセーフ コードが必要です。プロジェクトは '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' で更新する必要があります。 @@ -1277,4 +1312,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index baa3e6381b26d7..1cbdc68ed114d5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -147,6 +147,16 @@ 'EnableComHosting'을 사용한 .NET COM 호스팅은 'GeneratedComInterfaceAttribute'를 사용한 인터페이스를 지원하지 않습니다. + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. 관리 정의의 반환 값은 관리되지 않는 COM 메서드를 호출할 때 'out' 매개 변수로 변환됩니다. 반환 값이 관리되지 않는 COM 메서드에서 반환된 HRESULT 코드인 경우 메서드에서 '[PreserveSig]'를 사용하세요. @@ -447,6 +457,11 @@ 이 형식은 네이티브 HRESULT가 아니라 네이티브 서명의 구조체로 처리됩니다. + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. '[Out]' 특성도 사용되지 않는 한 '[In]' 특성은 지원되지 않습니다. Blittable 배열은 '[In]'으로만 마샬링할 수 없습니다. @@ -467,6 +482,11 @@ 이 매개 변수에 제공된 '[In]' 및 '[Out]' 특성은 이 매개 변수에서 지원되지 않습니다. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] 및 [Out] 속성 @@ -702,6 +722,16 @@ 잘못된 'VirtualMethodIndexAttribute' 사용 + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource'에서 반환된 'ReadOnlySpan'의 요소 형식은 'GetManagedValuesDestination'에서 반환된 요소 형식과 동일해야 합니다. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - '[Out]' 특성은 배열 매개 변수에서만 지원됩니다. 매개 변수를 변경할 수 있도록 'out' 또는 'ref' 키워드를 사용하는 것이 좋습니다. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ 형식 '{0}'은(는) 'Out' 방향으로 마샬링을 지원하도록 지정하지만 관리 형식을 반환하는 'ToManaged' 메서드를 제공하지 않습니다. + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' 및 'GeneratedComClassAttribute'에는 안전하지 않은 코드가 필요합니다. 프로젝트를 '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'로 업데이트해야 합니다. @@ -1276,4 +1311,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index 5f5447d2cd1ec5..05433b6de67407 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -147,6 +147,16 @@ Hosting modelu COM platformy .NET z elementem „EnableComHosting” nie obsługuje interfejsów z atrybutem „GeneratedComInterfaceAttribute” + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Wartość zwracana w definicji zarządzanej zostanie przekonwertowana na parametr „out” podczas wywoływania niezarządzanej metody COM. Jeśli wartość zwracana ma być kodem HRESULT zwracanym przez niezarządzaną metodę COM, należy użyć „[PreserveSig]” w metodzie. @@ -447,6 +457,11 @@ Ten typ będzie traktowany jako struktura w podpisie natywnym, a nie jako natywny wynik HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Atrybut „[In]” nie jest obsługiwany, chyba że używany jest również atrybut „[Out]”. Tablice kopiowalne nie mogą być kierowane tylko jako „[In]”. @@ -467,6 +482,11 @@ Podane atrybuty „[In]” i „[Out]” w tym parametrze nie są obsługiwane w tym parametrze. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Atrybuty [In] i [Out] @@ -702,6 +722,16 @@ Nieprawidłowe użycie atrybutu „VirtualMethodIndexAttribute” + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Typ elementu „ReadOnlySpan” zwracany przez element „GetManagedValuesSource” musi być taki sam jak typ elementu zwracany przez element „GetManagedValuesDestination”. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Atrybut „[Out]” jest obsługiwany tylko w przypadku parametrów tablicy. Rozważ użycie słów kluczowych „out” lub „ref”, aby umożliwić modyfikowanie parametru. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Atrybut „[Out]” jest obsługiwany tylko w przypadku parametrów tablicy. Rozważ użycie słów kluczowych „out” lub „ref”, aby umożliwić modyfikowanie parametru. @@ -917,6 +947,11 @@ Typ „{0}” określa, że obsługuje skierowanie w kierunku „Out”, ale nie zapewnia metody „ToManaged”, która zwraca typ zarządzany + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. Atrybut „GeneratedComInterfaceAttribute” i „GeneratedComClassAttribute” wymagają niebezpiecznego kodu. Projekt musi zostać zaktualizowany za pomocą polecenia „<AllowUnsafeBlocks>true</AllowUnsafeBlocks>”. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index 5eac2e488d6ee1..c608ba0d78a585 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -147,6 +147,16 @@ A hospedagem .NET COM com 'EnableComHosting' não dá suporte a interfaces com 'GeneratedComInterfaceAttribute' + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. O valor de retorno na definição gerenciada será convertido em um parâmetro 'out' ao chamar o método COM não gerenciado. Se o valor de retorno for o código HRESULT retornado pelo método COM não gerenciado, use '[PreserveSig]' no método. @@ -447,6 +457,11 @@ Este tipo será tratado como uma estrutura na assinatura nativa, não como um HRESULT nativo + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. O atributo '[In]' não é suportado, a menos que o atributo '[Out]' também seja usado. Matrizes Blittable não podem ser empacotadas apenas como '[In]'. @@ -467,6 +482,11 @@ Os atributos '[In]' e '[Out]' neste parâmetro não têm suporte neste parâmetro. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Atributos [In] e [Out] @@ -702,6 +722,16 @@ Uso de 'VirtualMethodIndexAttribute' inválido + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. O tipo de elemento de 'ReadOnlySpan' retornado por 'GetManagedValuesSource' deve ser igual ao tipo de elemento retornado por 'GetManagedValuesDestination'. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - O atributo "[Out]" só tem suporte em parâmetros de matriz. Considere usar palavras-chave "out" ou "ref" para tornar o parâmetro mutável. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ O tipo '{0}' especifica que ele dá suporte a marshalling na direção 'Out', mas não fornece um método 'ToManaged' que retorna o tipo gerenciado + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. "GeneratedComInterfaceAttribute" e "GeneratedComClassAttribute" exigem código não seguro. O projeto deve ser atualizado com "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>". @@ -1276,4 +1311,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf index 3c763338f053c4..bee98c1d72e1f8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf @@ -147,6 +147,16 @@ Размещение .NET COM с "EnableComHosting" не поддерживает интерфейсы с "GeneratedComInterfaceAttribute" + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Возвращаемое значение в управляемом определении будет преобразовано в параметр "out" при вызове неуправляемого метода COM. Если возвращаемое значение должно быть кодом HRESULT, возвращаемым неуправляемым COM-методом, используйте "[PreserveSig]" в методе. @@ -447,6 +457,11 @@ Этот тип будет рассматриваться как структура в собственной подписи, а не как собственный HRESULT. + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. Атрибут "[In]" не поддерживается, если также не используется атрибут "[Out]". Преобразуемые массивы нельзя сортировать только как "[In]". @@ -467,6 +482,11 @@ Указанные атрибуты \"[In]\" и \"[Out]\" для этого параметра не поддерживаются. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes Атрибуты [In] и [Out] @@ -702,6 +722,16 @@ Недопустимое использование VirtualMethodIndexAttribute + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. Тип элемента \"ReadOnlySpan\", возвращенный методом \"GetManagedValuesSource\", должен совпадать с типом элемента, возвращаемым методом \"GetManagedValuesDestination\". @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Атрибут "[Out]" поддерживается только для параметров массива. Рассмотрите возможность использования ключевых слов "out" или "ref", чтобы сделать параметр изменяемым. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Атрибут "[Out]" поддерживается только для параметров массива. Рассмотрите возможность использования ключевых слов "out" или "ref", чтобы сделать параметр изменяемым. @@ -917,6 +947,11 @@ Тип \"{0}\" указывает, что поддерживает маршализацию в направлении \"наружу\", но не предоставляет метод \"ToManaged\", который возвращает управляемый тип + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. Для "GeneratedComInterfaceAttribute" и "GeneratedComClassAttribute" требуется небезопасный код. Проект необходимо обновить с использованием значения "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>". diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf index b3551845a81494..ba0b8468207011 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf @@ -147,6 +147,16 @@ 'EnableComHosting' ile barındırma .NET COM, 'GeneratedComInterfaceAttribute' ile arabirimleri desteklemez + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. Yönetilen tanımdaki dönüş değeri, yönetilmeyen COM yöntemi çağrılırken 'out' parametresine dönüştürülür. Dönüş değerinin yönetilmeyen COM yöntemi tarafından döndürülen HRESULT kodu olması amaçlanmışsa, yöntemde '[PreserveSig]' kullanın. @@ -447,6 +457,11 @@ Bu tür, yerel HRESULT olarak değil, yerel imzada bir yapı olarak değerlendirilir + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. '[Out]' özniteliği de kullanılmadığı sürece '[In]' özniteliği desteklenmez. Blittable dizileri yalnızca '[In]' olarak hazırlanamaz. @@ -467,6 +482,11 @@ Bu parametrede sağlanan '[In]' ve '[Out]' öznitelikleri bu parametrede desteklenmiyor. + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] ve [Out] öznitelikleri @@ -702,6 +722,16 @@ Geçersiz 'VirtualMethodIndexAttribute' kullanımı + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource' tarafından döndürülen 'ReadOnlySpan' öğe türü, 'GetManagedValuesDestination' tarafından döndürülen öğe türüyle aynı olmalıdır. @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - '[Out]' özniteliği yalnızca dizi parametrelerinde desteklenir. Parametreyi değiştirilebilir yapmak için 'out' veya 'ref' anahtar sözcükleri kullanmayı düşünün. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + '[Out]' özniteliği yalnızca dizi parametrelerinde desteklenir. Parametreyi değiştirilebilir yapmak için 'out' veya 'ref' anahtar sözcükleri kullanmayı düşünün. @@ -917,6 +947,11 @@ '{0}' türü, 'Out' yönünde sıralamayı desteklediğini belirtiyor, ancak yönetilen türü döndüren bir 'ToManaged' metodu sağlamıyor + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' ve 'GeneratedComClassAttribute' güvenli olmayan kod gerektiriyor. Projenin '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' ile güncelleştirilmiş olması gerekiyor. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf index 5f77e5d137a900..fd82f97082b4d8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -147,6 +147,16 @@ 具有“EnableComHosting”的 .NET COM 托管不支持具有“GeneratedComInterfaceAttribute”的接口 + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. 调用非托管 COM 方法时,托管定义中的返回值将转换为 "out" 参数。如果返回值是非托管 COM 方法返回的 HRESULT 代码,请对方法使用 "[PreserveSig]"。 @@ -447,6 +457,11 @@ 此类型将被视为本机签名中的结构,而不是本机 HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. 不支持“[In]”属性,除非也使用“[Out]”属性。不能仅将 Blittable 数组封送为“[In]”。 @@ -467,6 +482,11 @@ 此参数上提供的 “[In]” 和 “[Out]” 属性在此参数上不受支持。 + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] 和 [Out] 属性 @@ -702,6 +722,16 @@ “VirtualMethodIndexAttribute” 使用情况无效 + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. “GetManagedValuesSource” 返回的 “ReadOnlySpan” 的元素类型必须与 “GetManagedValuesDestination” 返回的元素类型相同。 @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - `[Out]` 属性仅在数组参数上受支持。请考虑使用“out”或“ref”关键字使参数可变。 + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. @@ -917,6 +947,11 @@ 类型“{0}”指定它支持按 “Out” 方向进行封送,但不提供返回托管类型的 “ToManaged” 方法 + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. “GeneratedComInterfaceAttribute”和“GeneratedComClassAttribute”需要不安全代码。必须将项目更新为“<AllowUnsafeBlocks>true</AllowUnsafeBlocks>”。 @@ -1276,4 +1311,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf index 30be4f574082e7..a1998a248b2fdf 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -147,6 +147,16 @@ 以 'EnableComHosting' 裝載的 .NET COM 不支援具有 'GeneratedComInterfaceAttribute' 的介面 + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + + + + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + + The return value in the managed definition will be converted to an 'out' parameter when calling the unmanaged COM method. If the return value is intended to be the HRESULT code returned by the unmanaged COM method, use '[PreserveSig]' on the method. 呼叫未受控 COM 方法時,受控定義中的傳回值將轉換為 'out' 參數。如果傳回值預期是未受控 COM 方法傳回的 HRESULT 代碼,請在方法上使用 '[PreserveSig]'。 @@ -447,6 +457,11 @@ 此類型會被視為原生簽章中的結構,而非原生 HRESULT + + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + + The '[In]' attribute is not supported unless the '[Out]' attribute is also used. Blittable arrays cannot be marshalled as '[In]' only. 除非也使用 '[Out]' 屬性,否則不支援 '[In]' 屬性。無法只將 Blittable 陣列整理為 '[In]'。 @@ -467,6 +482,11 @@ 此參數不支援在此參數上提供的 '[In]' 和 '[Out]' 屬性。 + + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + + [In] and [Out] attributes [In] 與 [Out] 屬性 @@ -702,6 +722,16 @@ 'VirtualMethodIndexAttribute' 使用方式無效 + + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + + + + The usage of 'LibraryImportAttribute' does not follow recommendations. + The usage of 'LibraryImportAttribute' does not follow recommendations. + + The element type of the 'ReadOnlySpan' returned by 'GetManagedValuesSource' must be the same as the element type returned by 'GetManagedValuesDestination'. 'GetManagedValuesSource' 傳回的 'ReadOnlySpan' 元素類型必須與 'GetManagedValuesDestination' 傳回的元素類型相同。 @@ -903,8 +933,8 @@ - The `[Out]` attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - 只有陣列參數才支援 '[Out]' 屬性。請考慮使用 'out' 或 'ref' 關鍵字將參數設為可變。 + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + 只有陣列參數才支援 '[Out]' 屬性。請考慮使用 'out' 或 'ref' 關鍵字將參數設為可變。 @@ -917,6 +947,11 @@ 類型 '{0}' 指定它支援以 'Out' 方向排列,但未提供傳回受管理類型的 'ToManaged' 方法 + + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + + 'GeneratedComInterfaceAttribute' and 'GeneratedComClassAttribute' require unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. 'GeneratedComInterfaceAttribute' 和 'GeneratedComClassAttribute' 需要不安全的程式碼。專案必須以 '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>' 更新。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs index 2bef64490f9a4e..eb9a0237307bc3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DiagnosticDescriptorProvider.cs @@ -24,6 +24,7 @@ internal sealed class DiagnosticDescriptorProvider : IDiagnosticDescriptorProvid GeneratorDiagnostic.NotSupported { NotSupportedDetails: not null, TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo, GeneratorDiagnostic.UnnecessaryData { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.UnnecessaryReturnMarshallingInfo, + GeneratorDiagnostic.NotRecommended => GeneratorDiagnostics.LibraryImportUsageDoesNotFollowBestPractices, { IsFatal: false } => null, { TypePositionInfo.IsManagedReturnPosition: true } => GeneratorDiagnostics.ReturnTypeNotSupported, { TypePositionInfo.IsManagedReturnPosition: false } => GeneratorDiagnostics.ParameterTypeNotSupported, diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs index 2af2abadcdd607..f5fd78d48e587c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/GeneratorDiagnostics.cs @@ -254,6 +254,16 @@ public class Ids DiagnosticSeverity.Warning, isEnabledByDefault: true); + /// + public static readonly DiagnosticDescriptor LibraryImportUsageDoesNotFollowBestPractices = + new DiagnosticDescriptor( + Ids.NotRecommendedGeneratedComInterfaceUsage, + GetResourceString(nameof(SR.LibraryImportUsageDoesNotFollowBestPracticesTitle)), + GetResourceString(nameof(SR.LibraryImportUsageDoesNotFollowBestPracticesMessageWithDetails)), + Category, + DiagnosticSeverity.Info, + isEnabledByDefault: true); + /// /// Report diagnostic for invalid configuration for string marshalling. /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs index 123d649c913cd5..5455510ac356c0 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/IncrementalValuesProviderExtensions.cs @@ -47,7 +47,7 @@ public static IncrementalValuesProvider SelectNormalized(this Incr return provider.Select((node, ct) => node.NormalizeWhitespace()); } - public static (IncrementalValuesProvider, IncrementalValuesProvider) Split(this IncrementalValuesProvider<(T, T2)> provider) + public static (IncrementalValuesProvider, IncrementalValuesProvider) Split(this IncrementalValuesProvider<(T, T2)> provider) { return (provider.Select(static (data, ct) => data.Item1), provider.Select(static (data, ct) => data.Item2)); } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs index 73b8cd8eb901a9..69180eca11c190 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/AttributedMarshallingModelGeneratorFactory.cs @@ -431,17 +431,10 @@ private ResolvedGenerator CreateNativeCollectionMarshaller( { byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.Default; } - else if (!elementIsBlittable || ElementTypeIsSometimesNonBlittable(elementInfo)) - { - // If the type is not blittable or is sometimes not blittable, we will generate different code when the attributes are provided. - byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.ArrayParameter; - } else { - // If the type is always blittable, we'll generate the same code regardless of the attributes, - // but we'll allow them to make it easier to transition to source-generated code and allow users to be clear about expectations - // for values in pre-allocated buffers. - byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.PinnedParameter; + // If we have an array, we will use the Array [In, Out] support descriptor + byValueMarshalKindSupport = ByValueMarshalKindSupportDescriptor.ArrayParameter; } // Elements in the collection must be blittable to use the pinnable marshaller. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs index 5cc2a8f9a9b261..dd7a40fb8c90e2 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueContentsMarshalKindValidator.cs @@ -27,7 +27,7 @@ public ResolvedGenerator Create(TypePositionInfo info, StubCodeContext context) private static ResolvedGenerator ValidateByValueMarshalKind(TypePositionInfo info, StubCodeContext context, ResolvedGenerator generator) { - if (generator.Generator is Forwarder || info.ByValueContentsMarshalKind == ByValueContentsMarshalKind.Default) + if (generator.Generator is Forwarder) { // Forwarder allows everything since it just forwards to a P/Invoke. // The Default marshal kind is always valid. @@ -41,6 +41,7 @@ private static ResolvedGenerator ValidateByValueMarshalKind(TypePositionInfo inf ByValueMarshalKindSupport.Supported => generator, ByValueMarshalKindSupport.NotSupported => ResolvedGenerator.ResolvedWithDiagnostics(s_forwarder, generator.Diagnostics.Add(diagnostic!)), ByValueMarshalKindSupport.Unnecessary => generator with { Diagnostics = generator.Diagnostics.Add(diagnostic!) }, + ByValueMarshalKindSupport.NotRecommended => generator with { Diagnostics = generator.Diagnostics.Add(diagnostic!) }, _ => throw new UnreachableException() }; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs index 1f859d34ff919b..7754e177d66063 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/ByValueMarshalKindSupportDescriptor.cs @@ -3,127 +3,105 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; namespace Microsoft.Interop { + public record struct ByValueMarshalKindSupportInfo(ByValueMarshalKindSupport Support, string? details) + { + public ByValueMarshalKindSupport GetSupport(TypePositionInfo info, StubCodeContext context, out GeneratorDiagnostic? diagnostic) + { + diagnostic = Support switch + { + ByValueMarshalKindSupport.Supported => null, + ByValueMarshalKindSupport.NotRecommended => + new GeneratorDiagnostic.NotRecommended(info, context) + { + Details = details + }, + ByValueMarshalKindSupport.Unnecessary => + new GeneratorDiagnostic.UnnecessaryData( + info, + context, + ImmutableArray.Create(info.ByValueMarshalAttributeLocations.OutLocation)) + { + UnnecessaryDataName = SR.InOutAttributes, + UnnecessaryDataDetails = details + }, + ByValueMarshalKindSupport.NotSupported => + new GeneratorDiagnostic.NotSupported(info, context) + { + NotSupportedDetails = details + }, + _ => throw new UnreachableException() + }; + return Support; + } + } + /// /// Provides an implementation of through /// public record ByValueMarshalKindSupportDescriptor( - ByValueMarshalKindSupport InSupport, string? InSupportDetails, - ByValueMarshalKindSupport OutSupport, string? OutSupportDetails, - ByValueMarshalKindSupport InOutSupport, string? InOutSupportDetails) + ByValueMarshalKindSupportInfo DefaultSupport, + ByValueMarshalKindSupportInfo InSupport, + ByValueMarshalKindSupportInfo OutSupport, + ByValueMarshalKindSupportInfo InOutSupport) { /// /// A default for by value parameters. [In] is allowed, but unnecessary. Out is not allowed. /// public static readonly ByValueMarshalKindSupportDescriptor Default = new ByValueMarshalKindSupportDescriptor( - InSupport: ByValueMarshalKindSupport.Unnecessary, InSupportDetails: SR.InAttributeOnlyIsDefault, - OutSupport: ByValueMarshalKindSupport.NotSupported, OutSupportDetails: SR.OutAttributeNotSupportedOnByValueParameters, - InOutSupport: ByValueMarshalKindSupport.NotSupported, InOutSupportDetails: SR.OutAttributeNotSupportedOnByValueParameters); + DefaultSupport: new(ByValueMarshalKindSupport.Supported, null), + InSupport: new(ByValueMarshalKindSupport.NotSupported, SR.InAttributeNotSupportedOnByValueParameters), + OutSupport: new(ByValueMarshalKindSupport.NotSupported, SR.OutAttributeNotSupportedOnByValueParameters), + InOutSupport: new(ByValueMarshalKindSupport.NotSupported, SR.InOutAttributeNotSupportedOnByValueParameters)); /// - /// A default for by value array parameters. [In] is allowed, but unnecessary. Out is allowed. + /// A default for by value array parameters. Default is allowed, but Not Recommended. [In], [Out], and [In, Out] are allowed /// public static readonly ByValueMarshalKindSupportDescriptor ArrayParameter = new ByValueMarshalKindSupportDescriptor( - InSupport: ByValueMarshalKindSupport.Unnecessary, InSupportDetails: SR.InAttributeOnlyIsDefault, - OutSupport: ByValueMarshalKindSupport.Supported, OutSupportDetails: null, - InOutSupport: ByValueMarshalKindSupport.Supported, InOutSupportDetails: null); - - /// - /// A default for pinned parameters. [In] is allowed, but unnecessary. Out is allowed. - /// - public static readonly ByValueMarshalKindSupportDescriptor PinnedParameter = new ByValueMarshalKindSupportDescriptor( - InSupport: ByValueMarshalKindSupport.Unnecessary, InSupportDetails: SR.InAttributeOnlyIsDefault, - OutSupport: ByValueMarshalKindSupport.Supported, OutSupportDetails: null, - InOutSupport: ByValueMarshalKindSupport.Supported, InOutSupportDetails: null); + DefaultSupport: new(ByValueMarshalKindSupport.NotRecommended, SR.PreferExplicitInOutAttributesOnArrays), + InSupport: new(ByValueMarshalKindSupport.Supported, null), + OutSupport: new(ByValueMarshalKindSupport.Supported, null), + InOutSupport: new(ByValueMarshalKindSupport.Supported, null)); /// /// Returns the support for the ByValueContentsMarshalKind, and if it is not , diagnostic is not null /// public ByValueMarshalKindSupport GetSupport(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, StubCodeContext context, out GeneratorDiagnostic? diagnostic) { - if (info.IsByRef && marshalKind != ByValueContentsMarshalKind.Default) + if (info.IsByRef) { - diagnostic = new GeneratorDiagnostic.NotSupported(info, context) + // ByRef with ByValue attributes is not allowed + if (marshalKind != ByValueContentsMarshalKind.Default) { - NotSupportedDetails = SR.InOutAttributeByRefNotSupported - }; - return ByValueMarshalKindSupport.NotSupported; - } - switch (marshalKind) - { - case ByValueContentsMarshalKind.Default: - diagnostic = null; - return ByValueMarshalKindSupport.Supported; - case ByValueContentsMarshalKind.Out: - diagnostic = OutSupport switch + diagnostic = new GeneratorDiagnostic.NotSupported(info, context) { - ByValueMarshalKindSupport.Supported => null, - ByValueMarshalKindSupport.Unnecessary - => new GeneratorDiagnostic.UnnecessaryData( - info, - context, - ImmutableArray.Create(info.ByValueMarshalAttributeLocations.OutLocation)) - { - UnnecessaryDataName = SR.InOutAttributes, - UnnecessaryDataDetails = OutSupportDetails - }, - ByValueMarshalKindSupport.NotSupported - => new GeneratorDiagnostic.NotSupported( - info, - context) - { NotSupportedDetails = OutSupportDetails }, - _ => throw new UnreachableException($"Unexpected {nameof(ByValueMarshalKindSupport)} Variant: {InOutSupport}") + NotSupportedDetails = SR.InOutAttributeByRefNotSupported }; - return OutSupport; - case ByValueContentsMarshalKind.In: - diagnostic = InSupport switch - { - ByValueMarshalKindSupport.Supported => null, - ByValueMarshalKindSupport.Unnecessary - => new GeneratorDiagnostic.UnnecessaryData( - info, - context, - ImmutableArray.Create(info.ByValueMarshalAttributeLocations.InLocation)) - { - UnnecessaryDataName = SR.InOutAttributes, - UnnecessaryDataDetails = InSupportDetails - }, - ByValueMarshalKindSupport.NotSupported - => new GeneratorDiagnostic.NotSupported( - info, - context) - { NotSupportedDetails = InSupportDetails }, - _ => throw new UnreachableException($"Unexpected {nameof(ByValueMarshalKindSupport)} Variant: {InOutSupport}") - }; - return InSupport; - case ByValueContentsMarshalKind.InOut: - diagnostic = InOutSupport switch - { - ByValueMarshalKindSupport.Supported => null, - ByValueMarshalKindSupport.Unnecessary - => new GeneratorDiagnostic.UnnecessaryData( - info, - context, - ImmutableArray.Create( - info.ByValueMarshalAttributeLocations.InLocation, - info.ByValueMarshalAttributeLocations.OutLocation)) - { - UnnecessaryDataName = SR.InOutAttributes, - UnnecessaryDataDetails = InOutSupportDetails - }, - ByValueMarshalKindSupport.NotSupported - => new GeneratorDiagnostic.NotSupported( - info, - context) - { NotSupportedDetails = InOutSupportDetails }, - _ => throw new UnreachableException($"Unexpected {nameof(ByValueMarshalKindSupport)} Variant: {InOutSupport}") - }; - return InOutSupport; - default: - throw new UnreachableException($"Unexpected {nameof(ByValueContentsMarshalKind)} variant: {marshalKind}"); + return ByValueMarshalKindSupport.NotSupported; + } + // ByRef with no ByValue attributes is supported + diagnostic = null; + return ByValueMarshalKindSupport.Supported; + } + // Return can never have In or Out attributes, so can assume valid ByValue attributes + if (info.ManagedIndex < 0) + { + Debug.Assert(marshalKind is ByValueContentsMarshalKind.Default); + diagnostic = null; + return ByValueMarshalKindSupport.Supported; } + + return marshalKind switch + { + ByValueContentsMarshalKind.Default => DefaultSupport.GetSupport(info, context, out diagnostic), + ByValueContentsMarshalKind.In => InSupport.GetSupport(info, context, out diagnostic), + ByValueContentsMarshalKind.Out => OutSupport.GetSupport(info, context, out diagnostic), + ByValueContentsMarshalKind.InOut => InOutSupport.GetSupport(info, context, out diagnostic), + _ => throw new UnreachableException() + }; } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs index 22444e79824c9b..02820335ec176e 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/GeneratorDiagnostic.cs @@ -62,5 +62,18 @@ public override DiagnosticInfo ToDiagnosticInfo(DiagnosticDescriptor descriptor, UnnecessaryDataDetails ?? ""); } } + + public sealed record NotRecommended(TypePositionInfo TypePositionInfo, StubCodeContext StubCodeContext) : GeneratorDiagnostic(TypePositionInfo, StubCodeContext, isFatal: false) + { + public string? Details { get; init; } + + public override DiagnosticInfo ToDiagnosticInfo(DiagnosticDescriptor descriptor, Location location, string elementName) + { + return DiagnosticInfo.Create( + descriptor, + location, + Details); + } + } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs index f5e8aacdaa3c15..598ba380028946 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/MarshallingGenerator.cs @@ -83,6 +83,10 @@ public enum ByValueMarshalKindSupport /// The provided is supported but does not change behavior from the default in this scenario. /// Unnecessary, + /// + /// The provided is supported but does not follow best practices. + /// + NotRecommended, } /// diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs index 45ef61f85dbc58..039d78ed350068 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/StaticPinnableManagedValueMarshaller.cs @@ -105,7 +105,7 @@ private IEnumerable GeneratePinningPath(TypePositionInfo info, public ByValueMarshalKindSupport SupportsByValueMarshalKind(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, StubCodeContext context, out GeneratorDiagnostic? diagnostic) { - return ByValueMarshalKindSupportDescriptor.PinnedParameter.GetSupport(marshalKind, info, context, out diagnostic); + return _innerMarshallingGenerator.SupportsByValueMarshalKind(marshalKind, info, context, out diagnostic); } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs new file mode 100644 index 00000000000000..fdd2d33d6e7d27 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ByValueContentsMarshalling.cs @@ -0,0 +1,301 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.Interop; +using Xunit; +using static Microsoft.Interop.UnitTests.TestUtils; +using StringMarshalling = System.Runtime.InteropServices.StringMarshalling; +using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + +namespace ComInterfaceGenerator.Unit.Tests +{ + public class ByValueContentsMarshalling + { + private static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) + => generator switch + { + GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), + GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ManagedObjectWrapper), + GeneratorKind.ComInterfaceGeneratorComObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ComObjectWrapper), + GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), + _ => throw new UnreachableException(), + }; + + public static IEnumerable ByValueMarshalAttributeOnValueTypes() + { + var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); + const string In = "[{|#1:InAttribute|}]"; + const string Out = "[{|#2:OutAttribute|}]"; + const string paramName = "p"; + const string MarshalAsU4 = "[MarshalAs(UnmanagedType.U4)]"; + const string MarshalAsU2 = "[MarshalAs(UnmanagedType.U2)]"; + + string p = $$"""{|#0:{{paramName}}|}"""; + var diagnostic = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails); + var outAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); + var inAttributeIsNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InAttributeNotSupportedOnByValueParameters, paramName); + var inOutAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InOutAttributeNotSupportedOnByValueParameters, paramName); + + DiagnosticResult[] InIsNotSupported = [inAttributeIsNotSupported]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "int", p), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "byte", p), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalAsU4, "bool", p), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalAsU2, "char", p), InIsNotSupported }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "string", p, (StringMarshalling.Utf8, null)), InIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In, "IntClass", p) + CodeSnippets.IntClassAndMarshaller, InIsNotSupported }; + + DiagnosticResult[] OutIsNotSupported = [outAttributeNotSupported]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "int", p), OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalAsU4, "bool", p), OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalAsU2, "char", p), OutIsNotSupported }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "string", p, (StringMarshalling.Utf8, null)), OutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out, "IntClass", p) + CodeSnippets.IntClassAndMarshaller, OutIsNotSupported }; + + DiagnosticResult[] InOutIsNotSupported = [inOutAttributeNotSupported]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "int", p), InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalAsU4, "bool", p), InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalAsU2, "char", p), InOutIsNotSupported }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "string", p, (StringMarshalling.Utf8, null)), InOutIsNotSupported }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out, "IntClass", p) + CodeSnippets.IntClassAndMarshaller, InOutIsNotSupported }; + + // Any ref keyword is okay for non-collection types + DiagnosticResult[] None = []; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "byte", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU4 + "out", "bool", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU2 + "out", "char", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "string", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("out", "IntClass", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "byte", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU4 + "in", "bool", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU2 + "in", "char", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "string", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("in", "IntClass", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "IntStruct", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "byte", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU4 + "ref", "bool", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsU2 + "ref", "char", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "string", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType("ref", "IntClass", p) + CodeSnippets.IntClassAndMarshaller, None }; + } + + public static IEnumerable ByValueMarshalAttributeOnPinnedMarshalledTypes() + { + var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); + const string In = "[{|#1:InAttribute|}]"; + const string Out = "[{|#2:OutAttribute|}]"; + const string paramName = "p"; + string p = $$"""{|#0:{{paramName}}|}"""; + const string Count = @"[MarshalUsing(ConstantElementCount = 10)]"; + const string MarshalAsBoolArray = "[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeConst = 10)]"; + const string MarshalUsingIntMarshaller = "[MarshalUsing(typeof(IntMarshaller), ElementIndirectionDepth = 1)]"; + const string MarshalUsingIntStructMarshaller = "[MarshalUsing(typeof(IntStructMarshaller), ElementIndirectionDepth = 1)]"; + const string MarshalUsingIntClassMarshaller = "[MarshalUsing(typeof(IntClassMarshaller), ElementIndirectionDepth = 1)]"; + + // Any explicit [In] or [Out] on an array is preferred and should not warn + DiagnosticResult[] None = []; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count, "string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count, "string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(In + Out + Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count, "string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Out + Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + // Array parameters without [In] or [Out] should provide an Info diagnostic + var preferExplicitAttributesDiagnostic = new DiagnosticResult(GeneratorDiagnostics.GeneratedComInterfaceUsageDoesNotFollowBestPractices) + .WithLocation(0) + .WithArguments(SR.PreferExplicitInOutAttributesOnArrays); + DiagnosticResult[] PreferInOutAttributes = [preferExplicitAttributesDiagnostic]; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "int[]", p), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "char[]", p, (StringMarshalling.Utf16, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "bool[]", p, (StringMarshalling.Utf16, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "int[]", p) + CodeSnippets.IntMarshaller, PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "string[]", p, (StringMarshalling.Utf16, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "string[]", p, (StringMarshalling.Utf8, null)), PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, PreferInOutAttributes }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, PreferInOutAttributes }; + + // Ref Kinds shouldn't warn + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "in bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "in int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "in string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "in IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "in IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "out bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "out int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "out string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "out IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "out IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref int[]", p), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref char[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalAsBoolArray, "ref bool[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(MarshalUsingIntMarshaller + Count, "ref int[]", p) + CodeSnippets.IntMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref string[]", p, (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count, "ref string[]", p, (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntStructMarshaller, "ref IntStruct[]", p) + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(Count + MarshalUsingIntClassMarshaller, "ref IntClass[]", p) + CodeSnippets.IntClassAndMarshaller, None }; + } + + public static IEnumerable ByValueMarshalAttributeOnCustomCollections() + { + var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); + const string In = "[{|#1:InAttribute|}]"; + const string Out = "[{|#2:OutAttribute|}]"; + const string paramName = "p"; + string p = $$"""{|#0:{{paramName}}|}"""; + const string CollectionMarshaller = "StatelessCollectionAllShapesMarshaller<,>"; + + var diagnostic = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails); + var outAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); + var inAttributeIsNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InAttributeNotSupportedOnByValueParameters, paramName); + var inOutAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InOutAttributeNotSupportedOnByValueParameters, paramName); + + DiagnosticResult[] InIsNotSupported = [inAttributeIsNotSupported]; + DiagnosticResult[] OutIsNotSupported = [outAttributeNotSupported]; + DiagnosticResult[] InOutIsNotSupported = [inOutAttributeNotSupported]; + DiagnosticResult[] None = []; + + yield return new object[] { ID(), Source("", "int"), None }; + yield return new object[] { ID(), Source("", "byte"), None }; + yield return new object[] { ID(), Source(MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), Source(MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), Source("", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), Source("", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), Source(MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + // [In] and [Out] are not allowed on custom collections + yield return new object[] { ID(), Source(In, "int"), InIsNotSupported }; + yield return new object[] { ID(), Source(In, "byte"), InIsNotSupported }; + yield return new object[] { ID(), Source(In + MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, InIsNotSupported }; + yield return new object[] { ID(), Source(In + MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, InIsNotSupported }; + yield return new object[] { ID(), Source(In, "string", (StringMarshalling.Utf16, null)), InIsNotSupported }; + yield return new object[] { ID(), Source(In, "string", (StringMarshalling.Utf8, null)), InIsNotSupported }; + yield return new object[] { ID(), Source(In + MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), InIsNotSupported }; + + yield return new object[] { ID(), Source(Out, "int"), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out, "byte"), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out + MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, OutIsNotSupported }; + yield return new object[] { ID(), Source(Out + MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, OutIsNotSupported }; + yield return new object[] { ID(), Source(Out, "string", (StringMarshalling.Utf16, null)), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out, "string", (StringMarshalling.Utf8, null)), OutIsNotSupported }; + yield return new object[] { ID(), Source(Out + MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), OutIsNotSupported }; + + yield return new object[] { ID(), Source(In + Out, "int"), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out, "byte"), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out + MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out + MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out, "string", (StringMarshalling.Utf16, null)), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out, "string", (StringMarshalling.Utf8, null)), InOutIsNotSupported }; + yield return new object[] { ID(), Source(In + Out + MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), InOutIsNotSupported }; + + // RefKind modifiers are okay + yield return new object[] { ID(), SourceWithRefKind("in", "", "int"), None }; + yield return new object[] { ID(), SourceWithRefKind("in", "", "byte"), None }; + yield return new object[] { ID(), SourceWithRefKind("in", MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("in", MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("in", "", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("in", "", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("in", MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + yield return new object[] { ID(), SourceWithRefKind("out", "", "int"), None }; + yield return new object[] { ID(), SourceWithRefKind("out", "", "byte"), None }; + yield return new object[] { ID(), SourceWithRefKind("out", MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("out", MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("out", "", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("out", "", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("out", MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + yield return new object[] { ID(), SourceWithRefKind("ref", "", "int"), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", "", "byte"), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", MarshalUsing("IntClassMarshaller", 1), "IntClass") + CodeSnippets.IntClassAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("ref", MarshalUsing("IntStructMarshaller", 1), "IntStruct") + CodeSnippets.IntStructAndMarshaller, None }; + yield return new object[] { ID(), SourceWithRefKind("ref", "", "string", (StringMarshalling.Utf16, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", "", "string", (StringMarshalling.Utf8, null)), None }; + yield return new object[] { ID(), SourceWithRefKind("ref", MarshalCollection(1), CodeSnippets.GetCustomCollectionType("int")), None }; + + string Source(string Attributes, string type, (StringMarshalling StringMarshalling, Type? StringMarshallingCustomType)? stringMarshalling = null) + => SourceWithRefKind("", Attributes, type, stringMarshalling); + + string SourceWithRefKind(string refKind, string Attributes, string type, (StringMarshalling StringMarshalling, Type? StringMarshallingCustomType)? stringMarshalling = null) + { + return codeSnippets.ByValueMarshallingOfType(Attributes + MarshalCollection(), CodeSnippets.GetCustomCollectionType(type), p, stringMarshalling) + CodeSnippets.CustomCollectionAndMarshaller; + } + static string MarshalUsing(string marshaller = CollectionMarshaller, int depth = 0) + => $"[MarshalUsing(typeof({marshaller}), ElementIndirectionDepth = {depth})]"; + static string MarshalCollection(int depth = 0) + => $"[MarshalUsing(typeof({CollectionMarshaller}), ElementIndirectionDepth = {depth}, ConstantElementCount = 10)]"; + } + + + + [Theory] + [MemberData(nameof(ByValueMarshalAttributeOnPinnedMarshalledTypes))] + [MemberData(nameof(ByValueMarshalAttributeOnValueTypes))] + [MemberData(nameof(ByValueMarshalAttributeOnCustomCollections))] + public async Task VerifyByValueMarshallingAttributeUsageInfoMessages(string id, string source, DiagnosticResult[] diagnostics) + { + _ = id; + VerifyComInterfaceGenerator.Test test = new(referenceAncillaryInterop: false) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, + }; + test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); + test.ExpectedDiagnostics.AddRange(diagnostics); + await test.RunAsync(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs index b013d8c26c4599..700797fcb3e888 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -12,12 +13,26 @@ namespace ComInterfaceGenerator.Unit.Tests { internal partial class CodeSnippets { + internal static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) + => generator switch + { + GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), + GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ManagedObjectWrapper), + GeneratorKind.ComInterfaceGeneratorComObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ComObjectWrapper), + GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), + _ => throw new UnreachableException(), + }; + private readonly IComInterfaceAttributeProvider _attributeProvider; public CodeSnippets(IComInterfaceAttributeProvider attributeProvider) { _attributeProvider = attributeProvider; } + public CodeSnippets(GeneratorKind generator) : this(GetAttributeProvider(generator)) + { + } + private string VirtualMethodIndex( int index, bool? ImplicitThisParameter = null, @@ -49,6 +64,51 @@ private string UnmanagedCallConv(Type[]? CallConvs = null) + arguments + "]"; } + public static string GetCustomCollectionType(string elementName) => $"StatelessCollectionAllShapes<{elementName}>"; + + public const string CustomCollectionAndMarshaller = CustomCollectionDefinition + CustomCollectionAllShapesMarshaller; + public const string CustomCollectionDefinition = """ + internal class StatelessCollectionAllShapes + { + public T _field; + } + """; + public const string CustomCollectionAllShapesMarshaller = """ + [ContiguousCollectionMarshaller] + [CustomMarshaller(typeof(StatelessCollectionAllShapes<>), MarshalMode.Default, typeof(StatelessCollectionAllShapesMarshaller<,>))] + internal unsafe static class StatelessCollectionAllShapesMarshaller where TUnmanagedElement : unmanaged + { + public static void Free(TUnmanagedElement* unmanaged) { } + + // ToUnmanaged + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(StatelessCollectionAllShapes managed, out int numElements) + => throw null; + public static System.ReadOnlySpan GetManagedValuesSource(StatelessCollectionAllShapes managed) // Can throw exceptions + => throw null; + public static System.Span GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged, int numElements) // Can throw exceptions + => throw null; + public static ref TUnmanagedElement* GetPinnableReference(StatelessCollectionAllShapes managed) + => throw null; + + // Caller Allocated buffer ToUnmanaged + public static int BufferSize { get; } = 10; + public static TUnmanagedElement* AllocateContainerForUnmanagedElements(StatelessCollectionAllShapes managed, System.Span buffer, out int numElements) + => throw null; + + // ToManaged + public static StatelessCollectionAllShapes AllocateContainerForManagedElements(TUnmanagedElement* unmanaged, int numElements) + => throw null; + public static System.Span GetManagedValuesDestination(StatelessCollectionAllShapes managed) + => throw null; + public static System.ReadOnlySpan GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements) + => throw null; + + //ToManaged Guaranteed marshalling + public static StatelessCollectionAllShapes AllocateContainerForManagedElementsFinally(TUnmanagedElement* unmanaged, int numElements) + => throw null; + } + """; + public static readonly string DisableRuntimeMarshalling = "[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]"; public static readonly string UsingSystemRuntimeInteropServicesMarshalling = "using System.Runtime.InteropServices.Marshalling;"; public const string IntMarshaller = """ diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj index 08ca1a56fa43c8..beda4af3a72283 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj @@ -33,6 +33,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs index 2e4d25da3837e5..331fa54117fb04 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices.Marshalling; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -14,6 +12,7 @@ using Microsoft.Interop; using Microsoft.Interop.UnitTests; using Xunit; +using static Microsoft.Interop.UnitTests.TestUtils; using StringMarshalling = System.Runtime.InteropServices.StringMarshalling; using VerifyComInterfaceGenerator = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; @@ -21,11 +20,6 @@ namespace ComInterfaceGenerator.Unit.Tests { public class CompileFails { - private static string ID( - [CallerLineNumber] int lineNumber = 0, - [CallerFilePath] string? filePath = null) - => TestUtils.GetFileLineName(lineNumber, filePath); - public static IEnumerable ComInterfaceGeneratorSnippetsToCompile() { CodeSnippets codeSnippets = new(new GeneratedComInterfaceAttributeProvider()); @@ -54,19 +48,9 @@ public async Task ValidateComInterfaceGeneratorSnippets(string id, string source await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, expectedDiagnostics); } - private static IComInterfaceAttributeProvider GetAttributeProvider(GeneratorKind generator) - => generator switch - { - GeneratorKind.VTableIndexStubGenerator => new VirtualMethodIndexAttributeProvider(), - GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ManagedObjectWrapper), - GeneratorKind.ComInterfaceGeneratorComObjectWrapper => new GeneratedComInterfaceAttributeProvider(System.Runtime.InteropServices.Marshalling.ComInterfaceOptions.ComObjectWrapper), - GeneratorKind.ComInterfaceGenerator => new GeneratedComInterfaceAttributeProvider(), - _ => throw new UnreachableException(), - }; - public static IEnumerable InvalidUnmanagedToManagedCodeSnippetsToCompile(GeneratorKind generator) { - CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + CodeSnippets codeSnippets = new(generator); string safeHandleMarshallerDoesNotSupportManagedToUnmanaged = string.Format(SR.ManagedToUnmanagedMissingRequiredMarshaller, "global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller"); string safeHandleMarshallerDoesNotSupportUnmanagedToManaged = string.Format(SR.UnmanagedToManagedMissingRequiredMarshaller, "global::System.Runtime.InteropServices.Marshalling.SafeHandleMarshaller"); @@ -98,7 +82,7 @@ public static IEnumerable InvalidUnmanagedToManagedCodeSnippetsToCompi DiagnosticResult invalidReturnTypeDiagnostic = VerifyComInterfaceGenerator.Diagnostic(GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails) .WithLocation(0) .WithArguments(marshallerDoesNotSupportManagedToUnmanaged, "Method"); - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(CodeSnippets.GetAttributeProvider(generator))); yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyOutParameter, new[] { invalidManagedToUnmanagedParameterDiagnostic } }; yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyReturnValue, new[] { invalidReturnTypeDiagnostic } }; yield return new object[] { ID(), customStructMarshallingCodeSnippets.Stateless.ByValueInParameter, new[] { invalidUnmanagedToManagedParameterDiagnostic } }; @@ -113,7 +97,7 @@ public static IEnumerable StringMarshallingCodeSnippets(GeneratorKind string CustomTypeSpecifiedWithNoStringMarshallingCustom = SR.InvalidStringMarshallingConfigurationNotCustom; string StringMarshallingMustMatchBase = SR.GeneratedComInterfaceStringMarshallingMustMatchBase; - CodeSnippets codeSnippets = new(GetAttributeProvider(generator)); + CodeSnippets codeSnippets = new(generator); (StringMarshalling, Type?) utf8Marshalling = (StringMarshalling.Utf8, null); (StringMarshalling, Type?) utf16Marshalling = (StringMarshalling.Utf16, null); (StringMarshalling, Type?) customUtf16Marshalling = (StringMarshalling.Custom, typeof(Utf16StringMarshaller)); @@ -342,7 +326,7 @@ public static IEnumerable InvalidManagedToUnmanagedCodeSnippetsToCompi { // Marshallers with only support for their expected places in the signatures in // UnmanagedToManaged marshal modes. - CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(GetAttributeProvider(generator))); + CustomStructMarshallingCodeSnippets customStructMarshallingCodeSnippets = new(new CodeSnippets.Bidirectional(CodeSnippets.GetAttributeProvider(generator))); yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyInParameter }; yield return new[] { ID(), customStructMarshallingCodeSnippets.Stateless.ByValueOutParameter }; @@ -543,272 +527,6 @@ public async Task VerifyInterfaceWithLessVisibilityThanInterfaceWarns(string id, await VerifyComInterfaceGenerator.VerifySourceGeneratorAsync(source, diagnostics); } - public static IEnumerable ByValueMarshalAttributeOnValueTypes() - { - var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); - const string inAttribute = "[{|#1:InAttribute|}]"; - const string outAttribute = "[{|#2:OutAttribute|}]"; - const string paramName = "p"; - string paramNameWithLocation = $$"""{|#0:{{paramName}}|}"""; - var inAttributeIsDefaultDiagnostic = new DiagnosticResult(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, paramName, SR.InAttributeOnlyIsDefault); - - - // [In] is default for all non-pinned marshalled types - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute, "int", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute, "byte", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + "[MarshalAs(UnmanagedType.U4)]", "bool", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + "[MarshalAs(UnmanagedType.U2)]", "char", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic } }; - - // [Out] is not allowed on value types passed by value - there is no indirection for the callee to make visible modifications. - var outAttributeNotSupportedOnValueParameters = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(outAttribute, "int", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters } }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute, "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(outAttribute + "[MarshalAs(UnmanagedType.U4)]", "bool", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(outAttribute, "[MarshalAs(UnmanagedType.U2)] char", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - // [In,Out] should only warn for Out attribute - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute+outAttribute, "int", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters } }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute+outAttribute, "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute + "[MarshalAs(UnmanagedType.U4)]", "bool", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute, "[MarshalAs(UnmanagedType.U2)] char", paramNameWithLocation), new DiagnosticResult[] { - outAttributeNotSupportedOnValueParameters - } }; - - // Any ref keyword is okay for value types - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "byte", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("", "[MarshalAs(UnmanagedType.U2)] out char", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "byte", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("", "[MarshalAs(UnmanagedType.U2)] in char", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "IntStruct", paramNameWithLocation) + CodeSnippets.IntStructAndMarshaller, - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "byte", paramNameWithLocation), - new DiagnosticResult[] {} - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("", "[MarshalAs(UnmanagedType.U2)] ref char", paramNameWithLocation), - new DiagnosticResult[] {} - }; - } - - public static IEnumerable ByValueMarshalAttributeOnReferenceTypes() - { - var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); - const string inAttribute = "[{|#1:InAttribute|}]"; - const string outAttribute = "[{|#2:OutAttribute|}]"; - const string paramName = "p"; - string paramNameWithLocation = $$"""{|#0:{{paramName}}|}"""; - var inAttributeIsDefaultDiagnostic = new DiagnosticResult(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, paramName, SR.InAttributeOnlyIsDefault); - - // [In] is default - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute, "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute, "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - - var outNotAllowedOnRefTypes = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); - - // [Out] is not allowed on strings - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute, "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { outNotAllowedOnRefTypes } - }; - - // [Out] warns on by value reference types - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute, "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { outNotAllowedOnRefTypes } - }; - - // [In,Out] is fine on classes - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute, "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { outNotAllowedOnRefTypes } - }; - - // All refkinds are okay on classes and strings - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("in", "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("out", "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "string", paramNameWithLocation, (StringMarshalling.Utf8, null)), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType("ref", "IntClass", paramNameWithLocation) + CodeSnippets.IntClassAndMarshaller, - new DiagnosticResult[] { } - }; - } - - public static IEnumerable ByValueMarshalAttributeOnPinnedMarshalledTypes() - { - var codeSnippets = new CodeSnippets(GetAttributeProvider(GeneratorKind.ComInterfaceGenerator)); - const string inAttribute = "[{|#1:InAttribute|}]"; - const string outAttribute = "[{|#2:OutAttribute|}]"; - const string paramName = "p"; - string paramNameWithLocation = $$"""{|#0:{{paramName}}|}"""; - const string constElementCount = @"[MarshalUsing(ConstantElementCount = 10)]"; - var inAttributeIsDefaultDiagnostic = new DiagnosticResult(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, paramName, SR.InAttributeOnlyIsDefault); - - yield return new object[] { ID(), codeSnippets.ByValueMarshallingOfType(inAttribute + constElementCount, "int[]", paramNameWithLocation), new DiagnosticResult[] { - inAttributeIsDefaultDiagnostic - }}; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + constElementCount, "char[]", paramNameWithLocation, (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - - // bools that are marshalled into a new array are in by default - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType( - inAttribute + "[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeConst = 10)]", - "bool[]", - paramNameWithLocation, - (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - // Overriding marshalling with a custom marshaller makes it not pinned - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute, "[MarshalUsing(typeof(IntMarshaller), ElementIndirectionDepth = 1), MarshalUsing(ConstantElementCount = 10)]int[]", paramNameWithLocation) + CodeSnippets.IntMarshaller, - new DiagnosticResult[] { inAttributeIsDefaultDiagnostic } - }; - - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute + constElementCount, "int[]", paramNameWithLocation), - new DiagnosticResult[] { } - }; - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(inAttribute + outAttribute + constElementCount, "char[]", paramNameWithLocation, (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { } - }; - - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute + constElementCount, "int[]", paramNameWithLocation), - new DiagnosticResult[] { } - }; - - yield return new object[] { - ID(), - codeSnippets.ByValueMarshallingOfType(outAttribute + constElementCount, "char[]", paramNameWithLocation, (StringMarshalling.Utf16, null)), - new DiagnosticResult[] { } - }; - } - - [Theory] - [MemberData(nameof(ByValueMarshalAttributeOnValueTypes))] - [MemberData(nameof(ByValueMarshalAttributeOnReferenceTypes))] - [MemberData(nameof(ByValueMarshalAttributeOnPinnedMarshalledTypes))] - public async Task VerifyByValueMarshallingAttributeUsage(string id, string source, DiagnosticResult[] diagnostics) - { - _ = id; - VerifyComInterfaceGenerator.Test test = new(referenceAncillaryInterop: false) - { - TestCode = source, - TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, - }; - test.ExpectedDiagnostics.AddRange(diagnostics); - await test.RunAsync(); - } - [Fact] public async Task VerifyNonPartialInterfaceWarns() { @@ -967,7 +685,7 @@ partial interface {|#0:J|} public static IEnumerable CountParameterIsOutSnippets() { - var g = GetAttributeProvider(GeneratorKind.ComInterfaceGenerator); + var g = CodeSnippets.GetAttributeProvider(GeneratorKind.ComInterfaceGenerator); CodeSnippets a = new(g); DiagnosticResult returnValueDiag = new DiagnosticResult(GeneratorDiagnostics.SizeOfInCollectionMustBeDefinedAtCallReturnValue) .WithLocation(1) diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs index 4d1ec3a5d2c7dd..cd065f54a48c0b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/TestUtils.cs @@ -1,10 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing; using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -15,6 +11,10 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; using Xunit; namespace Microsoft.Interop.UnitTests @@ -51,6 +51,10 @@ public enum TestTargetFramework public static class TestUtils { + public static string ID( + [CallerLineNumber] int lineNumber = 0, + [CallerFilePath] string? filePath = null) + => TestUtils.GetFileLineName(lineNumber, filePath); internal static string GetFileLineName( [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string? filePath = null) @@ -298,7 +302,7 @@ public void Stop() int count = Interlocked.Decrement(ref _count); if (count == 0) { - Environment.SetEnvironmentVariable(EnvVarName, null); + Environment.SetEnvironmentVariable(EnvVarName, null); } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs new file mode 100644 index 00000000000000..e632481d52109f --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/ByValueContentsMarshalling.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.Interop; +using Xunit; +using static Microsoft.Interop.UnitTests.TestUtils; +using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; + +namespace LibraryImportGenerator.UnitTests +{ + public class ByValueContentsMarshalling + { + public static IEnumerable ByValueMarshalAttributeOnValueTypes() + { + CodeSnippets.ByValueParameterWithModifier("int[]", "In"); + + const string In = "InAttribute"; + const string Out = "OutAttribute"; + const string InOut = "InAttribute, OutAttribute"; + const string paramName = "p"; + const string MarshalUsingUtf16 = "MarshalUsing(typeof(Utf16StringMarshaller))"; + + var diagnostic = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails); + var outAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, paramName); + var inAttributeIsNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InAttributeNotSupportedOnByValueParameters, paramName); + var inOutAttributeNotSupported = diagnostic + .WithLocation(0) + .WithArguments(SR.InOutAttributeNotSupportedOnByValueParameters, paramName); + + DiagnosticResult[] InIsNotSupported = [inAttributeIsNotSupported]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int", In), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte", In), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string", In + " , " + MarshalUsingUtf16), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct", In, CodeSnippets.IntStructAndMarshaller), InIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass", In, CodeSnippets.IntClassAndMarshaller), InIsNotSupported }; + + DiagnosticResult[] OutIsNotSupported = [outAttributeNotSupported]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int", Out), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte", Out), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string", Out + " , " + MarshalUsingUtf16), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct", Out, CodeSnippets.IntStructAndMarshaller), OutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass", Out, CodeSnippets.IntClassAndMarshaller), OutIsNotSupported }; + + DiagnosticResult[] InOutIsNotSupported = [inOutAttributeNotSupported]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int", InOut), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte", InOut), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string", InOut + " , " + MarshalUsingUtf16), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct", InOut, CodeSnippets.IntStructAndMarshaller), InOutIsNotSupported }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass", InOut, CodeSnippets.IntClassAndMarshaller), InOutIsNotSupported }; + + var inAndOutNotAllowedWithRefKind = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p"); + DiagnosticResult[] InAndOutNotAllowedWithRefKind = [inAndOutNotAllowedWithRefKind]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int", In), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", In), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", InOut), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int", Out), InAndOutNotAllowedWithRefKind }; + } + + public static IEnumerable ByValueMarshalAttributeOnArrays() + { + CodeSnippets.ByValueParameterWithModifier("int[]", "In"); + + const string In = "InAttribute"; + const string Out = "OutAttribute"; + const string InOut = "InAttribute, OutAttribute"; + const string MarshalUsingUtf16 = "MarshalUsing(typeof(Utf16StringMarshaller), ElementIndirectionDepth = 1)"; + const string Count = "MarshalUsing(ConstantElementCount = 10)"; + DiagnosticResult[] None = []; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", string.Join(',', Count, In)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", string.Join(',', Count, In)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, In, MarshalUsingUtf16)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", string.Join(',', Count, In), CodeSnippets.IntStructAndMarshaller), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", string.Join(',', Count, In), CodeSnippets.IntClassAndMarshaller), None }; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", string.Join(',', Count, Out)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", string.Join(',', Count, Out)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, Out, MarshalUsingUtf16)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", string.Join(',', Count, Out), CodeSnippets.IntStructAndMarshaller), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", string.Join(',', Count, Out), CodeSnippets.IntClassAndMarshaller), None }; + + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", string.Join(',', Count, InOut)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", string.Join(',', Count, InOut)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, InOut, MarshalUsingUtf16)), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", string.Join(',', Count, InOut), CodeSnippets.IntStructAndMarshaller), None }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", string.Join(',', Count, InOut), CodeSnippets.IntClassAndMarshaller), None }; + + DiagnosticResult preferAttributes = new DiagnosticResult(GeneratorDiagnostics.LibraryImportUsageDoesNotFollowBestPractices) + .WithArguments(SR.PreferExplicitInOutAttributesOnArrays) + .WithLocation(0); + DiagnosticResult[] PreferAttributes = [preferAttributes]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("int[]", Count), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("byte[]", Count), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("string[]", string.Join(',', Count, MarshalUsingUtf16)), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntStruct[]", Count, CodeSnippets.IntStructAndMarshaller), PreferAttributes }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("IntClass[]", Count, CodeSnippets.IntClassAndMarshaller), PreferAttributes }; + + var inAndOutNotAllowedWithRefKind = new DiagnosticResult(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) + .WithLocation(0) + .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p"); + DiagnosticResult[] InAndOutNotAllowedWithRefKind = [inAndOutNotAllowedWithRefKind]; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int[]", string.Join(',', Count, In)), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int[]", string.Join(',', Count, In)), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int[]", string.Join(',', Count, In, Out)), InAndOutNotAllowedWithRefKind }; + yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int[]", string.Join(',', Count, Out)), InAndOutNotAllowedWithRefKind }; + } + + + [Theory] + [MemberData(nameof(ByValueMarshalAttributeOnValueTypes))] + [MemberData(nameof(ByValueMarshalAttributeOnArrays))] + public async Task VerifyByValueMarshallingAttributeUsageInfoMessages(string id, string source, DiagnosticResult[] diagnostics) + { + _ = id; + VerifyCS.Test test = new(referenceAncillaryInterop: false) + { + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck, + }; + test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); + test.ExpectedDiagnostics.AddRange(diagnostics); + await test.RunAsync(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs index e1039f70a90ef9..19832861a38aaa 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CodeSnippets.cs @@ -986,6 +986,22 @@ out int pOutSize } """; + public const string IntClassAndMarshaller = IntClassDefinition + IntClassMarshallerDefinition; + public const string IntClassDefinition = """ + internal struct IntClass + { + public int Field; + } + """; + public const string IntClassMarshallerDefinition = """ + [CustomMarshaller(typeof(IntClass), MarshalMode.Default, typeof(IntClassMarshaller))] + internal static class IntClassMarshaller + { + public static nint ConvertToUnmanaged(IntClass managed) => (nint)0; + public static IntClass ConvertToManaged(nint unmanaged) => default; + } + """; + public const string IntStructAndMarshaller = IntStructDefinition + IntStructMarshallerDefinition; public const string IntStructDefinition = """ internal struct IntStruct diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs index ffb3fb5c6a14ba..2d278dc6237de2 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/CompileFails.cs @@ -350,56 +350,6 @@ public static IEnumerable CodeSnippetsToCompile() .WithArguments("MarshalAsAttribute", "t") }}; - // Unsupported [In, Out] attributes usage - - // By ref with [In, Out] attributes - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("in int", "In"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("ref int", "In, Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("out int", "Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments("The '[In]' and '[Out]' attributes are unsupported on parameters passed by reference. Use the 'in', 'ref', or 'out' keywords instead.", "p") - } }; - - // By value non-array with [In, Out] attributes - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#1:In|}"), new [] { - VerifyCS.Diagnostic(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(1) - .WithArguments(SR.InOutAttributes, "p", SR.InAttributeOnlyIsDefault) - .WithSeverity(DiagnosticSeverity.Info) - } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, "p") - } }; - - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("In, Out"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails) - .WithLocation(0) - .WithArguments(SR.OutAttributeNotSupportedOnByValueParameters, "p") - } }; - // LCIDConversion yield return new object[] { ID(), CodeSnippets.LCIDConversionAttribute, new[] { VerifyCS.Diagnostic(GeneratorDiagnostics.ConfigurationNotSupported) @@ -832,13 +782,6 @@ public static IEnumerable CodeSnippetsToCompile() .WithLocation(1) .WithArguments("ref return", "Basic.RefReadonlyReturn()"), } }; - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:In|}"), new[] - { - VerifyCS.Diagnostic(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(10) - .WithArguments("[In] and [Out] attributes", "p", SR.InAttributeOnlyIsDefault) - } }; } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs index 438d589b2c29d0..5d37fffd52a5b6 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/Compiles.cs @@ -17,7 +17,6 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.Interop.UnitTests; using Xunit; -using GeneratorDiagnostics = Microsoft.Interop.GeneratorDiagnostics; using VerifyCS = Microsoft.Interop.UnitTests.Verifiers.CSharpSourceGeneratorVerifier; namespace LibraryImportGenerator.UnitTests @@ -744,28 +743,5 @@ public NoChangeTest(TestTargetFramework framework) return (newCompilation, diagnostics); } } - - public static IEnumerable ByValueMarshalKindSnippets() - { - // Blittable array - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:Out|}"), new DiagnosticResult[] { } }; - - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:In|}, {|#11:Out|}"), new DiagnosticResult[] { } }; - - yield return new object[] { ID(), CodeSnippets.ByValueParameterWithModifier("{|#10:In|}"), new DiagnosticResult[] { - VerifyCS.Diagnostic(GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo) - .WithLocation(0) - .WithLocation(10) - .WithArguments("[In] and [Out] attributes", "p", SR.InAttributeOnlyIsDefault) - } }; - } - - [MemberData(nameof(ByValueMarshalKindSnippets))] - [Theory] - public async Task ValidateDiagnosticsForUnnecessaryByValueMarshalKindAttributes(string id, string source, DiagnosticResult[] diagnostics) - { - _ = id; - await VerifyCS.VerifySourceGeneratorAsync(source, diagnostics); - } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj index c68eadac7ca4b4..cb767939315c84 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/SharedTypes/SharedTypes.csproj @@ -11,6 +11,8 @@ + + From 8cc9e079965da81a12cc5b4f35bc8549310f0ab7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 10:14:40 -0700 Subject: [PATCH 097/345] Remove AD0001 NoWarn from Microsoft.Extensions.Logging.Abstractions project (#91236) Co-authored-by: Buyaa Namnan --- .../src/Microsoft.Extensions.Logging.Abstractions.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj index db0c78fb49df05..085cade3966b96 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj @@ -4,8 +4,6 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true true - - $(NoWarn);AD0001 true Logging abstractions for Microsoft.Extensions.Logging. From bbaba10171c0e8d26b9d31877799d2ebe309c7ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 10:15:34 -0700 Subject: [PATCH 098/345] [release/8.0] Add Retry and Task.Delay to WinHttpHandler AfterReadResponseServerError_ClientWrite test (#91271) * Add Task.Delay to give more time for reset frame * Apply James' solution --------- Co-authored-by: Ahmet Ibrahim Aksoy (from Dev Box) --- .../FunctionalTests/BidirectionStreamingTest.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs index d18de54bc46cba..ce79f20ad4efec 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/BidirectionStreamingTest.cs @@ -143,7 +143,17 @@ public async Task AfterReadResponseServerError_ClientWrite() // Server sends RST_STREAM. await connection.WriteFrameAsync(new RstStreamFrame(FrameFlags.EndStream, 0, streamId)); - await Assert.ThrowsAsync(() => requestStream.WriteAsync(new byte[50]).AsTask()); + await Assert.ThrowsAsync(async () => + { + for (int i = 0; i < 10; i++) + { + await requestStream.WriteAsync(new byte[50]); + + // WriteAsync succeeded because handler hasn't processed RST_STREAM yet. + // Small wait before trying again. + await Task.Delay(50); + } + }); } } From 605cd300339f1c127c2c46aac425822d2cdeeb68 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 10:27:15 -0700 Subject: [PATCH 099/345] [release/8.0] JIT: Fix various HW intrinsic lowerings for unused values (#91266) * JIT: Fix LowerHWIntrinsicToScalar with unused values Fix #91173 * Fix more cases --------- Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/lowerarmarch.cpp | 4 +++ src/coreclr/jit/lowerxarch.cpp | 45 ++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index 86a5b2b1ab4cb4..2536d44aa00c56 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -1900,6 +1900,10 @@ GenTree* Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) { use.ReplaceWith(tmp2); } + else + { + tmp2->SetUnusedValue(); + } BlockRange().Remove(node); return tmp2->gtNext; diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index eba7bdb93e20fb..c1b5079f124545 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -3868,6 +3868,10 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) { use.ReplaceWith(newIndir); } + else + { + newIndir->SetUnusedValue(); + } BlockRange().Remove(op1); BlockRange().Remove(node); @@ -3916,6 +3920,10 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) { use.ReplaceWith(lclFld); } + else + { + lclFld->SetUnusedValue(); + } BlockRange().Remove(op1); BlockRange().Remove(op2); @@ -4158,6 +4166,11 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) { use.ReplaceWith(cast); } + else + { + node->ClearUnusedValue(); + cast->SetUnusedValue(); + } next = LowerNode(cast); } @@ -4737,6 +4750,10 @@ GenTree* Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) { use.ReplaceWith(tmp1); } + else + { + tmp1->SetUnusedValue(); + } BlockRange().Remove(node); return LowerNode(tmp1); @@ -5267,6 +5284,10 @@ GenTree* Lowering::LowerHWIntrinsicDot(GenTreeHWIntrinsic* node) { use.ReplaceWith(tmp1); } + else + { + tmp1->SetUnusedValue(); + } BlockRange().Remove(node); return tmp1->gtNext; @@ -5314,6 +5335,10 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) { use.ReplaceWith(newIndir); } + else + { + newIndir->SetUnusedValue(); + } BlockRange().Remove(op1); BlockRange().Remove(node); @@ -5342,6 +5367,10 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) { use.ReplaceWith(lclFld); } + else + { + lclFld->SetUnusedValue(); + } BlockRange().Remove(op1); BlockRange().Remove(node); @@ -5426,6 +5455,11 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) { use.ReplaceWith(cast); } + else + { + node->ClearUnusedValue(); + cast->SetUnusedValue(); + } next = LowerNode(cast); } @@ -8332,8 +8366,15 @@ void Lowering::TryFoldCnsVecForEmbeddedBroadcast(GenTreeHWIntrinsic* parentNode, BlockRange().InsertBefore(broadcastNode, createScalar); BlockRange().InsertBefore(createScalar, constScalar); LIR::Use use; - BlockRange().TryGetUse(childNode, &use); - use.ReplaceWith(broadcastNode); + if (BlockRange().TryGetUse(childNode, &use)) + { + use.ReplaceWith(broadcastNode); + } + else + { + broadcastNode->SetUnusedValue(); + } + BlockRange().Remove(childNode); LowerNode(createScalar); LowerNode(broadcastNode); From 2ec0bc7f0bbbe1bd7323fbbb00a549bf9cbae215 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 10:34:36 -0700 Subject: [PATCH 100/345] [release/8.0] [mono] Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods (#91059) * Extend mono_gsharedvt_constrained_call JIT icall to handle static virtual methods * Handle static virtual calls in constrained_gsharedvt_call_setup * Fix lint * Add runtime test * Remove runtime test --------- Co-authored-by: Milos Kotlar --- src/mono/mono/mini/jit-icalls.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index 04a15e94aea165..628d18abe35cfd 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -1358,7 +1358,7 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k error_init (error); - if (mono_class_is_interface (klass) || !m_class_is_valuetype (klass)) { + if ((mono_class_is_interface (klass) || !m_class_is_valuetype (klass)) && !m_method_is_static (cmethod)) { MonoObject *this_obj; is_iface = mono_class_is_interface (klass); @@ -1390,7 +1390,12 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k } } - if (m_class_is_valuetype (klass) && (m->klass == mono_defaults.object_class || m->klass == m_class_get_parent (mono_defaults.enum_class) || m->klass == mono_defaults.enum_class)) { + if (m_method_is_static (cmethod)) { + /* + * Static calls don't have this arg + */ + *this_arg = NULL; + } else if (m_class_is_valuetype (klass) && (m->klass == mono_defaults.object_class || m->klass == m_class_get_parent (mono_defaults.enum_class) || m->klass == mono_defaults.enum_class)) { /* * Calling a non-vtype method with a vtype receiver, has to box. */ From c3a87405ada82d8424f2b713ebd3c5866a768bad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 13:14:33 -0700 Subject: [PATCH 101/345] [release/8.0] [Mono] Fix unsafe accessor related issue for full AOT (#91270) * Fix unsafe accessor related issue for full aot * Only skip for WRAPPER_SUBTYPE_UNSAFE_ACCESSOR --------- Co-authored-by: Fan Yang --- src/mono/mono/mini/aot-compiler.c | 10 ++++++---- src/mono/mono/mini/method-to-ir.c | 14 ++++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 1944a77d2c00b0..023cd6ce42b0b5 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -3844,10 +3844,12 @@ encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 else if (info->subtype == WRAPPER_SUBTYPE_UNSAFE_ACCESSOR) { encode_method_ref (acfg, info->d.unsafe_accessor.method, p, &p); encode_value (info->d.unsafe_accessor.kind, p, &p); - /* WISH: is there some kind of string heap token we could use here? */ - uint32_t len = (uint32_t) strlen (info->d.unsafe_accessor.member_name); - encode_value (len, p, &p); - encode_string (info->d.unsafe_accessor.member_name, p, &p); + if (info->d.unsafe_accessor.member_name) { + /* WISH: is there some kind of string heap token we could use here? */ + uint32_t len = (uint32_t) strlen (info->d.unsafe_accessor.member_name); + encode_value (len, p, &p); + encode_string (info->d.unsafe_accessor.member_name, p, &p); + } } else if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN) encode_signature (acfg, info->d.interp_in.sig, p, &p); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index e3605981bafcdf..dedc6804c3cbd8 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -6452,8 +6452,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b generic_context = &generic_container->context; cfg->generic_context = generic_context; - if (!cfg->gshared) - g_assert (!sig->has_type_parameters); + if (!cfg->gshared) { + gboolean check_type_parameter = TRUE; + if (method->wrapper_type == MONO_WRAPPER_OTHER) { + WrapperInfo *info = mono_marshal_get_wrapper_info (method); + g_assert (info); + if (info->subtype == WRAPPER_SUBTYPE_UNSAFE_ACCESSOR) + check_type_parameter = FALSE; + } + + if (check_type_parameter) + g_assert (!sig->has_type_parameters); + } if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) { g_assert (method->is_inflated); From 776a845159b69a665935bfc297942a86399cf28a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:26:14 -0700 Subject: [PATCH 102/345] Disable failing test (#91269) Co-authored-by: Fan Yang --- src/tests/issues.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index b867b9134b5732..e9485d290e2d5d 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2712,6 +2712,9 @@ https://github.com/dotnet/runtime/issues/82859 + + https://github.com/dotnet/runtime/issues/90605 + From dddf0d0f8260cde735e8469862eb031ed8413409 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 30 Aug 2023 01:26:43 +0200 Subject: [PATCH 103/345] backport 90388 to Net8 (#91201) --- .../sample/wasm/browser-advanced/index.html | 5 +- src/mono/sample/wasm/browser-advanced/main.js | 1 + .../wasm/browser-bench/appstart-frame.html | 3 -- .../sample/wasm/browser-bench/frame-main.js | 5 +- src/mono/wasm/features.md | 3 +- src/mono/wasm/runtime/exports.ts | 4 +- src/mono/wasm/runtime/globals.ts | 1 - src/mono/wasm/runtime/loader/assets.ts | 18 +++----- src/mono/wasm/runtime/loader/config.ts | 19 ++++---- src/mono/wasm/runtime/loader/exit.ts | 2 +- src/mono/wasm/runtime/loader/globals.ts | 1 + src/mono/wasm/runtime/loader/run.ts | 6 +-- src/mono/wasm/runtime/snapshot.ts | 23 ++++++++-- src/mono/wasm/runtime/startup.ts | 46 ++++++++----------- src/mono/wasm/runtime/types/internal.ts | 6 ++- 15 files changed, 74 insertions(+), 69 deletions(-) diff --git a/src/mono/sample/wasm/browser-advanced/index.html b/src/mono/sample/wasm/browser-advanced/index.html index c8961d7c715408..24d51ea29672d6 100644 --- a/src/mono/sample/wasm/browser-advanced/index.html +++ b/src/mono/sample/wasm/browser-advanced/index.html @@ -13,10 +13,7 @@ - - - - + diff --git a/src/mono/sample/wasm/browser-advanced/main.js b/src/mono/sample/wasm/browser-advanced/main.js index f95fcbf9903be6..b5c414322fefd0 100644 --- a/src/mono/sample/wasm/browser-advanced/main.js +++ b/src/mono/sample/wasm/browser-advanced/main.js @@ -31,6 +31,7 @@ try { // here we show how emscripten could be further configured // It is preferred to use specific 'with***' methods instead in all other cases. .withConfig({ + startupMemoryCache: true, resources: { modulesAfterConfigLoaded: { "advanced-sample.lib.module.js": "" diff --git a/src/mono/sample/wasm/browser-bench/appstart-frame.html b/src/mono/sample/wasm/browser-bench/appstart-frame.html index 5bb75e32aa1b75..481ffa4e27301f 100644 --- a/src/mono/sample/wasm/browser-bench/appstart-frame.html +++ b/src/mono/sample/wasm/browser-bench/appstart-frame.html @@ -12,9 +12,6 @@ - - - diff --git a/src/mono/sample/wasm/browser-bench/frame-main.js b/src/mono/sample/wasm/browser-bench/frame-main.js index c1042928d78d07..88358e0310a10b 100644 --- a/src/mono/sample/wasm/browser-bench/frame-main.js +++ b/src/mono/sample/wasm/browser-bench/frame-main.js @@ -31,6 +31,10 @@ try { } const runtime = await dotnet + .withConfig({ + maxParallelDownloads: 10000, + // diagnosticTracing:true, + }) .withModuleConfig({ printErr: () => undefined, print: () => undefined, @@ -38,7 +42,6 @@ try { if (window.parent != window) { window.parent.resolveAppStartEvent("onConfigLoaded"); } - // config.diagnosticTracing = true; } }) .create(); diff --git a/src/mono/wasm/features.md b/src/mono/wasm/features.md index 46aa26d85038e1..c131002dde7968 100644 --- a/src/mono/wasm/features.md +++ b/src/mono/wasm/features.md @@ -193,12 +193,13 @@ See also [fetch integrity on MDN](https://developer.mozilla.org/en-US/docs/Web/A ### Pre-fetching In order to start downloading application resources as soon as possible you can add HTML elements to `` of your page similar to: +Adding too many files into prefetch could be counterproductive. +Please benchmark your startup performance on real target devices and with realistic network conditions. ```html - ``` See also [link rel prefetch on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/prefetch) diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index a29fd2da59d84f..6e50e26e164c0c 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -8,7 +8,7 @@ import type { RuntimeAPI } from "./types"; import { Module, linkerDisableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals"; import { GlobalObjects, is_nullish } from "./types/internal"; -import { configureEmscriptenStartup, configureWorkerStartup } from "./startup"; +import { configureEmscriptenStartup, configureRuntimeStartup, configureWorkerStartup } from "./startup"; import { create_weak_ref } from "./weak-ref"; import { export_internal } from "./exports-internal"; @@ -143,5 +143,5 @@ class RuntimeList { // export external API export { - passEmscriptenInternals, initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals + passEmscriptenInternals, initializeExports, initializeReplacements, configureRuntimeStartup, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals }; \ No newline at end of file diff --git a/src/mono/wasm/runtime/globals.ts b/src/mono/wasm/runtime/globals.ts index 5db69fc91bf619..b14bafd5ed2d7b 100644 --- a/src/mono/wasm/runtime/globals.ts +++ b/src/mono/wasm/runtime/globals.ts @@ -59,7 +59,6 @@ export function setRuntimeGlobals(globalObjects: GlobalObjects) { gitHash, allAssetsInMemory: createPromiseController(), dotnetReady: createPromiseController(), - memorySnapshotSkippedOrDone: createPromiseController(), afterInstantiateWasm: createPromiseController(), beforePreInit: createPromiseController(), afterPreInit: createPromiseController(), diff --git a/src/mono/wasm/runtime/loader/assets.ts b/src/mono/wasm/runtime/loader/assets.ts index ba18815a08db80..be7c0e4592938b 100644 --- a/src/mono/wasm/runtime/loader/assets.ts +++ b/src/mono/wasm/runtime/loader/assets.ts @@ -78,8 +78,6 @@ const containedInSnapshotByAssetTypes: { "pdb": true, "heap": true, "icu": true, - ...jsModulesAssetTypes, - "dotnetwasm": true, }; // these assets are instantiated differently than the main flow @@ -95,7 +93,7 @@ export function shouldLoadIcuAsset(asset: AssetEntryInternal): boolean { return !(asset.behavior == "icu" && asset.name != loaderHelpers.preferredIcuAsset); } -function convert_single_asset(modulesAssets: AssetEntryInternal[], resource: ResourceList | undefined, behavior: SingleAssetBehaviors): AssetEntryInternal { +function convert_single_asset(assetsCollection: AssetEntryInternal[], resource: ResourceList | undefined, behavior: SingleAssetBehaviors): AssetEntryInternal { const keys = Object.keys(resource || {}); mono_assert(keys.length == 1, `Expect to have one ${behavior} asset in resources`); @@ -110,7 +108,7 @@ function convert_single_asset(modulesAssets: AssetEntryInternal[], resource: Res set_single_asset(asset); // so that we can use it on the worker too - modulesAssets.push(asset); + assetsCollection.push(asset); return asset; } @@ -168,15 +166,12 @@ export async function mono_download_assets(): Promise { countAndStartDownload(asset); } - // continue after the dotnet.runtime.js was loaded - await loaderHelpers.runtimeModuleLoaded.promise; - // continue after we know if memory snapshot is available or not - await runtimeHelpers.memorySnapshotSkippedOrDone.promise; + await loaderHelpers.memorySnapshotSkippedOrDone.promise; // start fetching assets in parallel, only if memory snapshot is not available. for (const asset of containedInSnapshotAssets) { - if (!runtimeHelpers.loadedMemorySnapshot) { + if (!runtimeHelpers.loadedMemorySnapshotSize) { countAndStartDownload(asset); } else { // Otherwise cleanup in case we were given pending download. It would be even better if we could abort the download. @@ -193,6 +188,8 @@ export async function mono_download_assets(): Promise { } loaderHelpers.allDownloadsQueued.promise_control.resolve(); + + // continue after the dotnet.runtime.js was loaded await loaderHelpers.runtimeModuleLoaded.promise; const promises_of_asset_instantiation: Promise[] = []; @@ -211,7 +208,6 @@ export async function mono_download_assets(): Promise { // wait till after onRuntimeInitialized and after memory snapshot is loaded or skipped await runtimeHelpers.beforeOnRuntimeInitialized.promise; - await runtimeHelpers.memorySnapshotSkippedOrDone.promise; runtimeHelpers.instantiate_asset(asset, url, data); } } else { @@ -284,7 +280,7 @@ export function prepareAssets() { mono_assert(resources.jsModuleNative, "resources.jsModuleNative must be defined"); mono_assert(resources.jsModuleRuntime, "resources.jsModuleRuntime must be defined"); mono_assert(!MonoWasmThreads || resources.jsModuleWorker, "resources.jsModuleWorker must be defined"); - convert_single_asset(modulesAssets, resources.wasmNative, "dotnetwasm"); + convert_single_asset(alwaysLoadedAssets, resources.wasmNative, "dotnetwasm"); convert_single_asset(modulesAssets, resources.jsModuleNative, "js-module-native"); convert_single_asset(modulesAssets, resources.jsModuleRuntime, "js-module-runtime"); if (MonoWasmThreads) { diff --git a/src/mono/wasm/runtime/loader/config.ts b/src/mono/wasm/runtime/loader/config.ts index c35553ae593e8c..097f6d1ca2cb15 100644 --- a/src/mono/wasm/runtime/loader/config.ts +++ b/src/mono/wasm/runtime/loader/config.ts @@ -10,6 +10,7 @@ import { importLibraryInitializers, invokeLibraryInitializers } from "./libraryI import { mono_exit } from "./exit"; import { makeURLAbsoluteWithApplicationBase } from "./polyfills"; import { appendUniqueQuery } from "./assets"; +import { mono_assert } from "./globals"; export function deep_merge_config(target: MonoConfigInternal, source: MonoConfigInternal): MonoConfigInternal { // no need to merge the same object @@ -220,15 +221,12 @@ export async function mono_wasm_load_config(module: DotnetModuleInternal): Promi await loaderHelpers.afterConfigLoaded.promise; return; } - configLoaded = true; - if (!configFilePath) { - normalizeConfig(); - loaderHelpers.afterConfigLoaded.promise_control.resolve(loaderHelpers.config); - return; - } - mono_log_debug("mono_wasm_load_config"); try { - await loadBootConfig(module); + configLoaded = true; + if (configFilePath) { + mono_log_debug("mono_wasm_load_config"); + await loadBootConfig(module); + } normalizeConfig(); @@ -249,7 +247,12 @@ export async function mono_wasm_load_config(module: DotnetModuleInternal): Promi normalizeConfig(); + mono_assert(!loaderHelpers.config.startupMemoryCache || !module.instantiateWasm, "startupMemoryCache is not supported with Module.instantiateWasm"); + loaderHelpers.afterConfigLoaded.promise_control.resolve(loaderHelpers.config); + if (!loaderHelpers.config.startupMemoryCache) { + loaderHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); + } } catch (err) { const errMessage = `Failed to load config file ${configFilePath} ${err} ${(err as Error)?.stack}`; loaderHelpers.config = module.config = Object.assign(loaderHelpers.config, { message: errMessage, error: err, isError: true }); diff --git a/src/mono/wasm/runtime/loader/exit.ts b/src/mono/wasm/runtime/loader/exit.ts index e8cb2e42eb2ef1..6b6767e89672e6 100644 --- a/src/mono/wasm/runtime/loader/exit.ts +++ b/src/mono/wasm/runtime/loader/exit.ts @@ -122,9 +122,9 @@ function abort_promises(reason: any) { loaderHelpers.afterConfigLoaded.promise_control.reject(reason); loaderHelpers.wasmDownloadPromise.promise_control.reject(reason); loaderHelpers.runtimeModuleLoaded.promise_control.reject(reason); + loaderHelpers.memorySnapshotSkippedOrDone.promise_control.reject(reason); if (runtimeHelpers.dotnetReady) { runtimeHelpers.dotnetReady.promise_control.reject(reason); - runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.reject(reason); runtimeHelpers.afterInstantiateWasm.promise_control.reject(reason); runtimeHelpers.beforePreInit.promise_control.reject(reason); runtimeHelpers.afterPreInit.promise_control.reject(reason); diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts index a710ea0cb3b92d..55974cf4c51777 100644 --- a/src/mono/wasm/runtime/loader/globals.ts +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -87,6 +87,7 @@ export function setLoaderGlobals( allDownloadsQueued: createPromiseController(), wasmDownloadPromise: createPromiseController(), runtimeModuleLoaded: createPromiseController(), + memorySnapshotSkippedOrDone: createPromiseController(), is_exited, is_runtime_running, diff --git a/src/mono/wasm/runtime/loader/run.ts b/src/mono/wasm/runtime/loader/run.ts index a3cb7977a30f0c..b3437a5a81d61b 100644 --- a/src/mono/wasm/runtime/loader/run.ts +++ b/src/mono/wasm/runtime/loader/run.ts @@ -454,10 +454,11 @@ function importModules() { } async function initializeModules(es6Modules: [RuntimeModuleExportsInternal, NativeModuleExportsInternal]) { - const { initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals, passEmscriptenInternals } = es6Modules[0]; + const { initializeExports, initializeReplacements, configureRuntimeStartup, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals, passEmscriptenInternals } = es6Modules[0]; const { default: emscriptenFactory } = es6Modules[1]; setRuntimeGlobals(globalObjectsRoot); initializeExports(globalObjectsRoot); + await configureRuntimeStartup(); loaderHelpers.runtimeModuleLoaded.promise_control.resolve(); emscriptenFactory((originalModule: EmscriptenModuleInternal) => { @@ -494,9 +495,8 @@ async function createEmscriptenMain(): Promise { mono_exit(1, err); }); - init_globalization(); - setTimeout(() => { + init_globalization(); mono_download_assets(); // intentionally not awaited }, 0); diff --git a/src/mono/wasm/runtime/snapshot.ts b/src/mono/wasm/runtime/snapshot.ts index 1d1df904643f51..c23422353a7dd3 100644 --- a/src/mono/wasm/runtime/snapshot.ts +++ b/src/mono/wasm/runtime/snapshot.ts @@ -44,22 +44,35 @@ async function openCache(): Promise { } } -export async function getMemorySnapshotSize(): Promise { +export async function checkMemorySnapshotSize(): Promise { try { + if (!runtimeHelpers.config.startupMemoryCache) { + // we could start downloading DLLs because snapshot is disabled + return; + } + const cacheKey = await getCacheKey(); if (!cacheKey) { - return undefined; + return; } const cache = await openCache(); if (!cache) { - return undefined; + return; } const res = await cache.match(cacheKey); const contentLength = res?.headers.get("content-length"); - return contentLength ? parseInt(contentLength) : undefined; + const memorySize = contentLength ? parseInt(contentLength) : undefined; + + runtimeHelpers.loadedMemorySnapshotSize = memorySize; + runtimeHelpers.storeMemorySnapshotPending = !memorySize; } catch (ex) { mono_log_warn("Failed find memory snapshot in the cache", ex); - return undefined; + } + finally { + if (!runtimeHelpers.loadedMemorySnapshotSize) { + // we could start downloading DLLs because there is no snapshot yet + loaderHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); + } } } diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index f67a8b7c18ba90..e6f8d80ef82f48 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -21,7 +21,7 @@ import { instantiate_wasm_asset, wait_for_all_assets } from "./assets"; import { mono_wasm_init_diagnostics } from "./diagnostics"; import { replace_linker_placeholders } from "./exports-binding"; import { endMeasure, MeasuredBlock, startMeasure } from "./profiler"; -import { getMemorySnapshot, storeMemorySnapshot, getMemorySnapshotSize } from "./snapshot"; +import { checkMemorySnapshotSize, getMemorySnapshot, storeMemorySnapshot } from "./snapshot"; import { mono_log_debug, mono_log_error, mono_log_warn, mono_set_thread_id } from "./logging"; // threads @@ -39,6 +39,19 @@ import { assertNoProxies } from "./gc-handles"; // default size if MonoConfig.pthreadPoolSize is undefined const MONO_PTHREAD_POOL_SIZE = 4; +export async function configureRuntimeStartup(): Promise { + if (linkerWasmEnableSIMD) { + mono_assert(await loaderHelpers.simd(), "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); + } + if (linkerWasmEnableEH) { + mono_assert(await loaderHelpers.exceptions(), "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); + } + + await init_polyfills_async(); + + await checkMemorySnapshotSize(); +} + // we are making emscripten startup async friendly // emscripten is executing the events without awaiting it and so we need to block progress via PromiseControllers above export function configureEmscriptenStartup(module: DotnetModuleInternal): void { @@ -117,8 +130,6 @@ function instantiateWasm( const mark = startMeasure(); if (userInstantiateWasm) { - // user wasm instantiation doesn't support memory snapshots - runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); const exports = userInstantiateWasm(imports, (instance: WebAssembly.Instance, module: WebAssembly.Module | undefined) => { endMeasure(mark, MeasuredBlock.instantiateWasm); runtimeHelpers.afterInstantiateWasm.promise_control.resolve(); @@ -375,14 +386,6 @@ async function mono_wasm_pre_init_essential_async(): Promise { mono_log_debug("mono_wasm_pre_init_essential_async"); Module.addRunDependency("mono_wasm_pre_init_essential_async"); - if (linkerWasmEnableSIMD) { - mono_assert(await loaderHelpers.simd(), "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); - } - if (linkerWasmEnableEH) { - mono_assert(await loaderHelpers.exceptions(), "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); - } - - await init_polyfills_async(); if (MonoWasmThreads) { preAllocatePThreadWorkerPool(MONO_PTHREAD_POOL_SIZE, runtimeHelpers.config); @@ -457,20 +460,9 @@ async function instantiate_wasm_module( ): Promise { // this is called so early that even Module exports like addRunDependency don't exist yet try { - let memorySize: number | undefined = undefined; await loaderHelpers.afterConfigLoaded; mono_log_debug("instantiate_wasm_module"); - if (runtimeHelpers.config.startupMemoryCache) { - memorySize = await getMemorySnapshotSize(); - runtimeHelpers.loadedMemorySnapshot = !!memorySize; - runtimeHelpers.storeMemorySnapshotPending = !runtimeHelpers.loadedMemorySnapshot; - } - if (!runtimeHelpers.loadedMemorySnapshot) { - // we should start downloading DLLs etc as they are not in the snapshot - runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); - } - await runtimeHelpers.beforePreInit.promise; Module.addRunDependency("instantiate_wasm_module"); @@ -484,19 +476,19 @@ async function instantiate_wasm_module( mono_log_debug("instantiate_wasm_module done"); - if (runtimeHelpers.loadedMemorySnapshot) { + if (runtimeHelpers.loadedMemorySnapshotSize) { try { const wasmMemory = (Module.asm?.memory || Module.wasmMemory)!; // .grow() takes a delta compared to the previous size - wasmMemory.grow((memorySize! - wasmMemory.buffer.byteLength + 65535) >>> 16); + wasmMemory.grow((runtimeHelpers.loadedMemorySnapshotSize! - wasmMemory.buffer.byteLength + 65535) >>> 16); runtimeHelpers.updateMemoryViews(); } catch (err) { mono_log_warn("failed to resize memory for the snapshot", err); - runtimeHelpers.loadedMemorySnapshot = false; + runtimeHelpers.loadedMemorySnapshotSize = undefined; } // now we know if the loading of memory succeeded or not, we can start loading the rest of the assets - runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); + loaderHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); } runtimeHelpers.afterInstantiateWasm.promise_control.resolve(); } catch (err) { @@ -509,7 +501,7 @@ async function instantiate_wasm_module( async function mono_wasm_before_memory_snapshot() { const mark = startMeasure(); - if (runtimeHelpers.loadedMemorySnapshot) { + if (runtimeHelpers.loadedMemorySnapshotSize) { // get the bytes after we re-sized the memory, so that we don't have too much memory in use at the same time const memoryBytes = await getMemorySnapshot(); const heapU8 = localHeapViewU8(); diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts index fcbeb03eadefdd..aedf803aceff1f 100644 --- a/src/mono/wasm/runtime/types/internal.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -128,6 +128,7 @@ export type LoaderHelpers = { allDownloadsQueued: PromiseAndController, wasmDownloadPromise: PromiseAndController, runtimeModuleLoaded: PromiseAndController, + memorySnapshotSkippedOrDone: PromiseAndController, is_exited: () => boolean, is_runtime_running: () => boolean, @@ -176,7 +177,7 @@ export type RuntimeHelpers = { mono_wasm_runtime_is_ready: boolean; mono_wasm_bindings_is_ready: boolean; - loadedMemorySnapshot: boolean, + loadedMemorySnapshotSize?: number, enablePerfMeasure: boolean; waitForDebugger?: number; ExitStatus: ExitStatusError; @@ -194,7 +195,6 @@ export type RuntimeHelpers = { allAssetsInMemory: PromiseAndController, dotnetReady: PromiseAndController, - memorySnapshotSkippedOrDone: PromiseAndController, afterInstantiateWasm: PromiseAndController, beforePreInit: PromiseAndController, afterPreInit: PromiseAndController, @@ -490,6 +490,7 @@ export type setGlobalObjectsType = (globalObjects: GlobalObjects) => void; export type initializeExportsType = (globalObjects: GlobalObjects) => RuntimeAPI; export type initializeReplacementsType = (replacements: EmscriptenReplacements) => void; export type configureEmscriptenStartupType = (module: DotnetModuleInternal) => void; +export type configureRuntimeStartupType = () => Promise; export type configureWorkerStartupType = (module: DotnetModuleInternal) => Promise @@ -497,6 +498,7 @@ export type RuntimeModuleExportsInternal = { setRuntimeGlobals: setGlobalObjectsType, initializeExports: initializeExportsType, initializeReplacements: initializeReplacementsType, + configureRuntimeStartup: configureRuntimeStartupType, configureEmscriptenStartup: configureEmscriptenStartupType, configureWorkerStartup: configureWorkerStartupType, passEmscriptenInternals: passEmscriptenInternalsType, From c7558999450da512074cae9b9ddf6470b4c53f07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:36:57 -0700 Subject: [PATCH 104/345] [release/8.0] Add boolean field to indicate whether or not the Windows thread pool is being used (#91246) * Add boolean field to indicate whether or not the Windows thread pool is being used * Update src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs Co-authored-by: Stephen Toub * Remove trailing spaces * Move comment * Update fields and comments * Disable CA1823 - unused field --------- Co-authored-by: unknown Co-authored-by: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Co-authored-by: Stephen Toub --- .../src/System/Threading/ThreadPool.Windows.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs index 6882b0482c017a..0da875498afc18 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs @@ -13,6 +13,12 @@ public static partial class ThreadPool internal static bool UseWindowsThreadPool { get; } = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.UseWindowsThreadPool", "DOTNET_ThreadPool_UseWindowsThreadPool"); +#pragma warning disable CA1823 + // The field should reflect what the property returns because the property can be stubbed by trimming, + // such that sos reflects the actual state of what thread pool is being used and not just the config value. + private static readonly bool s_useWindowsThreadPool = UseWindowsThreadPool; // Name relied on by sos +#pragma warning restore CA1823 + #if NATIVEAOT private const bool IsWorkerTrackingEnabledInConfig = false; #else From c00d0ff5ed3ea293567fca46de64bf129be823af Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:39:26 -0700 Subject: [PATCH 105/345] [release/8.0] Update dependencies from dotnet/cecil dotnet/arcade dotnet/hotreload-utils dotnet/source-build-reference-packages (#91264) * Update dependencies from https://github.com/dotnet/cecil build 20230828.2 Microsoft.DotNet.Cecil From Version 0.11.4-alpha.23421.1 -> To Version 0.11.4-alpha.23428.2 * Update dependencies from https://github.com/dotnet/arcade build 20230828.2 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23425.2 -> To Version 8.0.0-beta.23428.2 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20230828.3 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 8.0.0-alpha.0.23421.1 -> To Version 8.0.0-alpha.0.23428.3 * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230828.2 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23424.1 -> To Version 8.0.0-alpha.1.23428.2 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Larry Ewing --- eng/Version.Details.xml | 84 ++++++++++++++++++++--------------------- eng/Versions.props | 34 ++++++++--------- global.json | 6 +-- 3 files changed, 62 insertions(+), 62 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index aad708a98fcdce..efb4b40dceea8c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -85,9 +85,9 @@ 02fe27cd6a9b001c8feb7938e6ef4b3799745759b - + https://github.com/dotnet/cecil - d412306c1514a26737574838900052d8758da5be + fa5acbd2ccba88c9d46ce0dd8f5310f9d3c5c46d @@ -95,9 +95,9 @@ 66dbaefff04250dc72849f0172e0c53bcfb3ab38 - + https://github.com/dotnet/source-build-reference-packages - 93c23409e630c4f267234540b0e3557b76a53ef4 + 26ce96327dd346534926c4551f8b8d62a6fc724f @@ -107,9 +107,9 @@ - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 @@ -117,69 +117,69 @@ ed9a83526483c094fb51e7000b6f816ce6cb0325 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 https://github.com/dotnet/runtime-assets @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 90c167d5c57de4a8bced566379dbd893556c94e8 + 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -350,9 +350,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization ffa66bdcbd319c11795d23e835e7a44344723332 - + https://github.com/dotnet/hotreload-utils - e02247b9b7ec1d9e407312342147d8587a8ca20e + 4f453acb93d3340457a64b06a5f884adab76fd0b https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index 6414c8e37f55d0..6b31387aabe99d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,21 +85,21 @@ 8.0.100-preview.7.23329.3 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 2.5.1-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 - 8.0.0-beta.23425.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 2.5.1-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 + 8.0.0-beta.23428.2 6.0.0-preview.1.102 @@ -184,7 +184,7 @@ 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 - 8.0.0-alpha.0.23421.1 + 8.0.0-alpha.0.23428.3 2.4.2 1.0.0 2.4.5 @@ -213,7 +213,7 @@ 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23421.1 + 0.11.4-alpha.23428.2 8.0.0-rc.1.23406.6 diff --git a/global.json b/global.json index ffe9ed56766f48..fd45afe4dd2784 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23425.2", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23425.2", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23425.2", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23428.2", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23428.2", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23428.2", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From 36b3790bfc6fe077c4047aec0d64a0157c0c7928 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:40:25 -0700 Subject: [PATCH 106/345] [release/8.0] [browser] Add `EmccMaximumHeapSize` to define maximum memory (#91277) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * EmccMaximumHeapSize to define maximum memory * Fix typo in comment * Space in param use --------- Co-authored-by: Marek Fišera --- src/mono/wasm/build/WasmApp.Native.targets | 9 +++++---- src/mono/wasm/build/WasmApp.targets | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 7060397f0cb85c..295474566a14a0 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -221,10 +221,11 @@ <_EmccCommonFlags Include="$(_DefaultEmccFlags)" /> <_EmccCommonFlags Include="$(EmccFlags)" /> - <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> - <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" /> - <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> - <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> + <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> + <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" /> + <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> + <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> + <_EmccCommonFlags Include="-s MAXIMUM_MEMORY=$(EmccMaximumHeapSize)" Condition="'$(EmccMaximumHeapSize)' != ''" /> <_EmccIncludePaths Include="$(_WasmIntermediateOutputPath.TrimEnd('\/'))" /> <_EmccIncludePaths Include="$(_WasmRuntimePackIncludeDir)mono-2.0" /> diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index be1b7214e2c0bd..0a22f3f82d528f 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -57,6 +57,8 @@ - $(EmccInitialHeapSize) - Initial heap size specified with `emcc`. Default value: 16777216 or size of the DLLs, whichever is larger. Corresponds to `-s INITIAL_MEMORY=...` emcc arg. (previously named EmccTotalMemory, which is still kept as an alias) + - $(EmccMaximumHeapSize) - Maximum heap size specified with `emcc`. Default value: 2147483648 or size of the DLLs, whichever is larger. + Corresponds to `-s MAXIMUM_MEMORY=...` emcc arg. - $(EmccStackSize) - Stack size. Default value: 5MB. Corresponds to `-s STACK_SIZE=...` emcc arg. From 40d2134aa50389d70fd845a7a6c06f46383e602e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:13:55 -0700 Subject: [PATCH 107/345] [release/8.0] [mono][metadata] Replace use of mem manager lock with loader lock (#91327) * [mono][metadata] Replace use of mem manager lock with loader lock Hash table operations under the mem manager lock could end up taking the loader lock when performing type comparison, in the case where custom modifiers needed to be loaded. Use the loader lock instead to prevent deadlocks. * [mono][metadata] Use loader lock during generic class hash table lookup --------- Co-authored-by: Vlad Brezae --- src/mono/mono/metadata/metadata.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/metadata/metadata.c b/src/mono/mono/metadata/metadata.c index 7c7cd4433eecf6..f9abe652b019a3 100644 --- a/src/mono/mono/metadata/metadata.c +++ b/src/mono/mono/metadata/metadata.c @@ -3434,7 +3434,8 @@ mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate) MonoMemoryManager *mm = mono_mem_manager_get_generic (data.images, data.nimages); collect_data_free (&data); - mono_mem_manager_lock (mm); + // Hashtable key equal func can take loader lock + mono_loader_lock (); if (!mm->ginst_cache) mm->ginst_cache = g_hash_table_new_full (mono_metadata_generic_inst_hash, mono_metadata_generic_inst_equal, NULL, (GDestroyNotify)free_generic_inst); @@ -3456,7 +3457,7 @@ mono_metadata_get_canonical_generic_inst (MonoGenericInst *candidate) g_hash_table_insert (mm->ginst_cache, ginst, ginst); } - mono_mem_manager_unlock (mm); + mono_loader_unlock (); return ginst; } @@ -3467,7 +3468,8 @@ mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer *cand g_assert (candidate->count > 0); MonoMemoryManager *mm = mono_metadata_get_mem_manager_for_aggregate_modifiers (candidate); - mono_mem_manager_lock (mm); + // Hashtable key equal func can take loader lock + mono_loader_lock (); if (!mm->aggregate_modifiers_cache) mm->aggregate_modifiers_cache = g_hash_table_new_full (aggregate_modifiers_hash, aggregate_modifiers_equal, NULL, (GDestroyNotify)free_aggregate_modifiers); @@ -3484,7 +3486,7 @@ mono_metadata_get_canonical_aggregate_modifiers (MonoAggregateModContainer *cand g_hash_table_insert (mm->aggregate_modifiers_cache, amods, amods); } - mono_mem_manager_unlock (mm); + mono_loader_unlock (); return amods; } @@ -3543,7 +3545,8 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst if (gclass) return gclass; - mono_mem_manager_lock (mm); + // Hashtable key equal func can take loader lock + mono_loader_lock (); gclass = mono_mem_manager_alloc0 (mm, sizeof (MonoGenericClass)); if (is_dynamic) @@ -3563,7 +3566,7 @@ mono_metadata_lookup_generic_class (MonoClass *container_class, MonoGenericInst // g_hash_table_insert (set->gclass_cache, gclass, gclass); - mono_mem_manager_unlock (mm); + mono_loader_unlock (); return gclass2; } From e018fb7c957f1552aa967fe9a4c3ce715df6ed43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 12:40:56 -0700 Subject: [PATCH 108/345] Fix Http2 MultiConnection test race conditions (#91343) Co-authored-by: Miha Zupan --- ...lientHandlerTestBase.SocketsHttpHandler.cs | 17 ++ .../tests/FunctionalTests/MetricsTest.cs | 13 +- .../SocketsHttpHandlerTest.Cancellation.cs | 4 +- .../FunctionalTests/SocketsHttpHandlerTest.cs | 193 ++++++++---------- 4 files changed, 109 insertions(+), 118 deletions(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs index 602d177f5f1be1..888b38b813127e 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTestBase.SocketsHttpHandler.cs @@ -3,14 +3,31 @@ using System.IO; using System.Net.Quic; +using System.Net.Sockets; using System.Net.Test.Common; using System.Reflection; +using System.Threading; using System.Threading.Tasks; namespace System.Net.Http.Functional.Tests { public abstract partial class HttpClientHandlerTestBase : FileCleanupTestBase { + protected static async Task DefaultConnectCallback(EndPoint endPoint, CancellationToken cancellationToken) + { + Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; + try + { + await socket.ConnectAsync(endPoint, cancellationToken); + return new NetworkStream(socket, ownsSocket: true); + } + catch + { + socket.Dispose(); + throw; + } + } + protected static bool IsWinHttpHandler => false; public static bool IsQuicSupported diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs index f3a97d2f15d530..da36366246f415 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs @@ -292,17 +292,8 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => GetUnderlyingSocketsHttpHandler(Handler).ConnectCallback = async (ctx, cancellationToken) => { connectionStarted.SetResult(); - Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; - try - { - await socket.ConnectAsync(ctx.DnsEndPoint, cancellationToken); - return new NetworkStream(socket, ownsSocket: true); - } - catch - { - socket.Dispose(); - throw; - } + + return await DefaultConnectCallback(ctx.DnsEndPoint, cancellationToken); }; // Enable recording request-duration to test the path with metrics enabled. diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs index c793a1d55d6e76..76d7086c37c174 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.Cancellation.cs @@ -165,9 +165,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => else { // Succeed the second connection attempt - Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; - await socket.ConnectAsync(context.DnsEndPoint, token); - return new NetworkStream(socket, ownsSocket: true); + return await DefaultConnectCallback(context.DnsEndPoint, token); } }; diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index e25f69529b0e60..2613b451be4556 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -1369,17 +1369,7 @@ await RetryHelper.ExecuteAsync(async () => { Assert.Equal("foo", context.DnsEndPoint.Host); - Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; - try - { - await socket.ConnectAsync(lastServerUri.IdnHost, lastServerUri.Port); - return new NetworkStream(socket, ownsSocket: true); - } - catch - { - socket.Dispose(); - throw; - } + return await DefaultConnectCallback(new DnsEndPoint(lastServerUri.IdnHost, lastServerUri.Port), ct); }; TaskCompletionSource waitingForLastRequest = new(TaskCreationOptions.RunContinuationsAsynchronously); @@ -2659,30 +2649,18 @@ public async Task Http2_MultipleConnectionsEnabled_ManyRequestsEnqueuedSimultane AcquireAllStreamSlots(server, client, sendTasks, RequestCount); - List<(Http2LoopbackConnection connection, int streamId)> acceptedRequests = new(); - await using Http2LoopbackConnection c1 = await server.EstablishConnectionAsync(new SettingsEntry { SettingId = SettingId.MaxConcurrentStreams, Value = 100 }); - for (int i = 0; i < MaxConcurrentStreams; i++) - { - (int streamId, _) = await c1.ReadAndParseRequestHeaderAsync(); - acceptedRequests.Add((c1, streamId)); - } + int[] streamIds1 = await AcceptRequests(c1, MaxConcurrentStreams); await using Http2LoopbackConnection c2 = await server.EstablishConnectionAsync(new SettingsEntry { SettingId = SettingId.MaxConcurrentStreams, Value = 100 }); - for (int i = 0; i < MaxConcurrentStreams; i++) - { - (int streamId, _) = await c2.ReadAndParseRequestHeaderAsync(); - acceptedRequests.Add((c2, streamId)); - } + int[] streamIds2 = await AcceptRequests(c2, MaxConcurrentStreams); await using Http2LoopbackConnection c3 = await server.EstablishConnectionAsync(new SettingsEntry { SettingId = SettingId.MaxConcurrentStreams, Value = 100 }); (int finalStreamId, _) = await c3.ReadAndParseRequestHeaderAsync(); - acceptedRequests.Add((c3, finalStreamId)); - foreach ((Http2LoopbackConnection connection, int streamId) request in acceptedRequests) - { - await request.connection.SendDefaultResponseAsync(request.streamId); - } + await SendResponses(c1, streamIds1); + await SendResponses(c2, streamIds2); + await c3.SendDefaultResponseAsync(finalStreamId); await VerifySendTasks(sendTasks); } @@ -2702,19 +2680,17 @@ public async Task Http2_MultipleConnectionsEnabled_InfiniteRequestsCompletelyBlo Http2LoopbackConnection connection0 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); - // Block the first connection on infinite requests. + // Accept requests but don't send responses on connection 0 int[] blockedStreamIds = await AcceptRequests(connection0, MaxConcurrentStreams).ConfigureAwait(false); - Assert.Equal(MaxConcurrentStreams, blockedStreamIds.Length); Http2LoopbackConnection connection1 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); - await HandleAllPendingRequests(connection1, MaxConcurrentStreams).ConfigureAwait(false); + // Send responses on connection 1 + await SendResponses(connection1, await AcceptRequests(connection1, MaxConcurrentStreams).ConfigureAwait(false)); - // Complete infinite requests. - int handledRequestCount = await SendResponses(connection0, blockedStreamIds); - - Assert.Equal(MaxConcurrentStreams, handledRequestCount); + // Send responses on connection 0 + await SendResponses(connection0, blockedStreamIds); await VerifySendTasks(sendTasks).ConfigureAwait(false); } @@ -2729,44 +2705,62 @@ public async Task Http2_MultipleConnectionsEnabled_OpenAndCloseMultipleConnectio const int MaxConcurrentStreams = 2; using Http2LoopbackServer server = Http2LoopbackServer.CreateServer(); + server.AllowMultipleConnections = true; + + // Allow 5 connections through the ConnectCallback. + SemaphoreSlim connectCallbackSemaphore = new(initialCount: 5); + using SocketsHttpHandler handler = CreateHandler(); + + handler.ConnectCallback = async (context, ct) => + { + await connectCallbackSemaphore.WaitAsync(ct); + + return await DefaultConnectCallback(context.DnsEndPoint, ct); + }; + using (HttpClient client = CreateHttpClient(handler)) { - server.AllowMultipleConnections = true; - List> sendTasks = new List>(); + List> sendTasks = new(); + Http2LoopbackConnection connection0 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + int[] streamIds0 = await AcceptRequests(connection0, MaxConcurrentStreams).ConfigureAwait(false); + Http2LoopbackConnection connection1 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + int[] streamIds1 = await AcceptRequests(connection1, MaxConcurrentStreams).ConfigureAwait(false); + Http2LoopbackConnection connection2 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + int[] streamIds2 = await AcceptRequests(connection2, MaxConcurrentStreams).ConfigureAwait(false); - Task[] handleRequestTasks = new[] { - HandleAllPendingRequests(connection0, MaxConcurrentStreams), - HandleAllPendingRequests(connection1, MaxConcurrentStreams), - HandleAllPendingRequests(connection2, MaxConcurrentStreams) - }; - - await TestHelper.WhenAllCompletedOrAnyFailed(handleRequestTasks).ConfigureAwait(false); + await TestHelper.WhenAllCompletedOrAnyFailed( + SendResponses(connection0, streamIds0), + SendResponses(connection1, streamIds1), + SendResponses(connection2, streamIds2)) + .ConfigureAwait(false); - await connection0.ShutdownIgnoringErrorsAsync(await handleRequestTasks[0]).ConfigureAwait(false); - await connection2.ShutdownIgnoringErrorsAsync(await handleRequestTasks[2]).ConfigureAwait(false); + await connection0.ShutdownIgnoringErrorsAsync(streamIds0[^1]).ConfigureAwait(false); + await connection2.ShutdownIgnoringErrorsAsync(streamIds2[^1]).ConfigureAwait(false); - //Fill all connection1's stream slots + // Fill all connection1's stream slots AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + streamIds1 = await AcceptRequests(connection1, MaxConcurrentStreams).ConfigureAwait(false); Http2LoopbackConnection connection3 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + int[] streamIds3 = await AcceptRequests(connection3, MaxConcurrentStreams).ConfigureAwait(false); + Http2LoopbackConnection connection4 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + int[] streamIds4 = await AcceptRequests(connection4, MaxConcurrentStreams).ConfigureAwait(false); - Task[] finalHandleTasks = new[] { - HandleAllPendingRequests(connection1, MaxConcurrentStreams), - HandleAllPendingRequests(connection3, MaxConcurrentStreams), - HandleAllPendingRequests(connection4, MaxConcurrentStreams) - }; - - await TestHelper.WhenAllCompletedOrAnyFailed(finalHandleTasks).ConfigureAwait(false); + await TestHelper.WhenAllCompletedOrAnyFailed( + SendResponses(connection1, streamIds1), + SendResponses(connection3, streamIds3), + SendResponses(connection4, streamIds4)) + .ConfigureAwait(false); await VerifySendTasks(sendTasks).ConfigureAwait(false); } @@ -2778,24 +2772,36 @@ public async Task Http2_MultipleConnectionsEnabled_IdleConnectionTimeoutExpired_ { const int MaxConcurrentStreams = 2; using Http2LoopbackServer server = Http2LoopbackServer.CreateServer(); + server.AllowMultipleConnections = true; + + SemaphoreSlim connectCallbackSemaphore = new(initialCount: 2); + using SocketsHttpHandler handler = CreateHandler(); handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(20); + + handler.ConnectCallback = async (context, ct) => + { + await connectCallbackSemaphore.WaitAsync(ct); + + return await DefaultConnectCallback(context.DnsEndPoint, ct); + }; + using (HttpClient client = CreateHttpClient(handler)) { - server.AllowMultipleConnections = true; - List> sendTasks = new List>(); + List> sendTasks0 = new(); + List> sendTasks1 = new(); + List> sendTasks2 = new(); + Http2LoopbackConnection connection0 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); - AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); - int[] acceptedStreamIds = await AcceptRequests(connection0, MaxConcurrentStreams).ConfigureAwait(false); - Assert.Equal(MaxConcurrentStreams, acceptedStreamIds.Length); + AcquireAllStreamSlots(server, client, sendTasks0, MaxConcurrentStreams); + int[] streamIds0 = await AcceptRequests(connection0, MaxConcurrentStreams).ConfigureAwait(false); - List> connection1SendTasks = new List>(); Http2LoopbackConnection connection1 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); - AcquireAllStreamSlots(server, client, connection1SendTasks, MaxConcurrentStreams); - await HandleAllPendingRequests(connection1, MaxConcurrentStreams).ConfigureAwait(false); + AcquireAllStreamSlots(server, client, sendTasks1, MaxConcurrentStreams); + await SendResponses(connection1, await AcceptRequests(connection1, MaxConcurrentStreams).ConfigureAwait(false)); - // Complete all the requests. - await VerifySendTasks(connection1SendTasks).ConfigureAwait(false); + // Complete all the requests on connection1. + await VerifySendTasks(sendTasks1).ConfigureAwait(false); // Wait until the idle connection timeout expires. await connection1.WaitForClientDisconnectAsync(false).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); @@ -2803,17 +2809,20 @@ public async Task Http2_MultipleConnectionsEnabled_IdleConnectionTimeoutExpired_ Assert.True(connection1.IsInvalid); Assert.False(connection0.IsInvalid); - Http2LoopbackConnection connection2 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); - - AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); + // Due to a race condition in how a new Http2 connection is returned to the pool, we may have started a third connection attempt in the background. + // We were blocking such attempts from going through to the Socket layer until now to avoid having to deal with the extra connect when accepting connection2 below. + // Allow the third connection through the ConnectCallback now. + connectCallbackSemaphore.Release(); - await HandleAllPendingRequests(connection2, MaxConcurrentStreams).ConfigureAwait(false); + Http2LoopbackConnection connection2 = await PrepareConnection(server, client, MaxConcurrentStreams).ConfigureAwait(false); + AcquireAllStreamSlots(server, client, sendTasks2, MaxConcurrentStreams); + await SendResponses(connection2, await AcceptRequests(connection2, MaxConcurrentStreams).ConfigureAwait(false)); - //Make sure connection0 is still alive. - int handledRequests0 = await SendResponses(connection0, acceptedStreamIds).ConfigureAwait(false); - Assert.Equal(MaxConcurrentStreams, handledRequests0); + // Make sure connection0 is still alive. + await SendResponses(connection0, streamIds0).ConfigureAwait(false); - await VerifySendTasks(sendTasks).ConfigureAwait(false); + await VerifySendTasks(sendTasks0).ConfigureAwait(false); + await VerifySendTasks(sendTasks2).ConfigureAwait(false); } } @@ -2842,7 +2851,10 @@ private async Task PrepareConnection(Http2LoopbackServe Task warmUpTask = client.GetAsync(server.Address); - Http2LoopbackConnection connection = await GetConnection(server, maxConcurrentStreams).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); + var concurrentStreamsSetting = new SettingsEntry { SettingId = SettingId.MaxConcurrentStreams, Value = maxConcurrentStreams }; + + Http2LoopbackConnection connection = await server.EstablishConnectionAsync(timeout: null, ackTimeout: TimeSpan.FromSeconds(10), concurrentStreamsSetting) + .WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); (int streamId, _) = await connection.ReadAndParseRequestHeaderAsync().WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); await connection.SendDefaultResponseAsync(streamId).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); @@ -2862,49 +2874,25 @@ private static void AcquireAllStreamSlots(Http2LoopbackServer server, HttpClient } } - private static async Task GetConnection(Http2LoopbackServer server, uint maxConcurrentStreams) - { - var concurrentStreamsSetting = new SettingsEntry { SettingId = SettingId.MaxConcurrentStreams, Value = maxConcurrentStreams }; - - return await server.EstablishConnectionAsync(timeout: null, ackTimeout: TimeSpan.FromSeconds(10), concurrentStreamsSetting).ConfigureAwait(false); - } - - private async Task HandleAllPendingRequests(Http2LoopbackConnection connection, int totalRequestCount) - { - int lastStreamId = -1; - for (int i = 0; i < totalRequestCount; i++) - { - (int streamId, _) = await connection.ReadAndParseRequestHeaderAsync().ConfigureAwait(false); - await connection.SendDefaultResponseAsync(streamId).ConfigureAwait(false); - lastStreamId = streamId; - } - - return lastStreamId; - } - private async Task AcceptRequests(Http2LoopbackConnection connection, int requestCount) { int[] streamIds = new int[requestCount]; for (int i = 0; i < streamIds.Length; i++) { - (int streamId, _) = await connection.ReadAndParseRequestHeaderAsync().ConfigureAwait(false); + (int streamId, _) = await connection.ReadAndParseRequestHeaderAsync().WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); streamIds[i] = streamId; } return streamIds; } - private async Task SendResponses(Http2LoopbackConnection connection, IEnumerable streamIds) + private async Task SendResponses(Http2LoopbackConnection connection, IEnumerable streamIds) { - int count = 0; foreach (int streamId in streamIds) { - count++; - await connection.SendDefaultResponseAsync(streamId).ConfigureAwait(false); + await connection.SendDefaultResponseAsync(streamId).WaitAsync(TestHelper.PassingTestTimeout).ConfigureAwait(false); } - - return count; } } @@ -3108,10 +3096,7 @@ public async Task ConnectCallback_ConnectionPrefix_Success(bool useSsl) var socketsHandler = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler); socketsHandler.ConnectCallback = async (context, token) => { - Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - await clientSocket.ConnectAsync(listenSocket.LocalEndPoint); - - Stream clientStream = new NetworkStream(clientSocket, ownsSocket: true); + Stream clientStream = await DefaultConnectCallback(listenSocket.LocalEndPoint, token); await clientStream.WriteAsync(RequestPrefix); From 028b380d67b891a6f45d02d633145a0c7b58a857 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 12:43:07 -0700 Subject: [PATCH 109/345] [release/8.0] [browser] Update browser template to use Wasm SDK (#91046) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use WasmSdk in browser template * Remove default html-path * Use wwwroot when looking for main.js in template for replacement * Temporarily remove WasmRuntimeAssetsLocation from WBT because WasmSDK doesn't support it yet * Integrate console log forward into DevServer * Replace UseRouter * Use next middleware only if it's not console * CancellationTokenSource on CancelKeyPress * Address feedback from initial DevServer integration * Update src/mono/wasm/host/BrowserHost.cs Co-authored-by: Ankit Jain * Remove debugging code * Fix WBT * Fix starting outside of project directory * Support WasmRuntimeAssetsLocation in Wasm SDK * Revert "Support WasmRuntimeAssetsLocation in Wasm SDK" * Active issue for WasmRuntimeAssetsLocation * Feedback --------- Co-authored-by: Marek Fišera Co-authored-by: Ankit Jain --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 8 +++-- .../Templates/WasmTemplateTests.cs | 7 ++-- .../WasmSdkBasedProjectProvider.cs | 15 ++++++++ .../Wasm.Build.Tests/WasmTemplateTestBase.cs | 28 ++++++++++++--- src/mono/wasm/host/BrowserHost.cs | 4 +-- src/mono/wasm/host/DevServer/DevServer.cs | 3 +- .../wasm/host/DevServer/DevServerStartup.cs | 34 ++++++++++++++++--- src/mono/wasm/host/Program.cs | 3 ++ .../templates/templates/browser/README.md | 26 -------------- .../templates/browser/browser.0.csproj | 11 ++---- .../browser/runtimeconfig.template.json | 5 ++- .../browser/{ => wwwroot}/index.html | 0 .../templates/browser/{ => wwwroot}/main.js | 0 13 files changed, 88 insertions(+), 56 deletions(-) delete mode 100644 src/mono/wasm/templates/templates/browser/README.md rename src/mono/wasm/templates/templates/browser/{ => wwwroot}/index.html (100%) rename src/mono/wasm/templates/templates/browser/{ => wwwroot}/main.js (100%) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index f8898000dab693..324f36cad7957f 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -19,9 +19,13 @@ Copyright (c) .NET Foundation. All rights reserved. dotnet $([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), '..', 'WasmAppHost')) - <_RuntimeConfigJsonPath>$([MSBuild]::NormalizePath($(OutputPath), '$(AssemblyName).runtimeconfig.json')) + + <_RunWorkingDirectory>$(OutputPath) + <_RunWorkingDirectory Condition="'$(_RunWorkingDirectory)' != '' and !$([System.IO.Path]::IsPathRooted($(_RunWorkingDirectory)))">$([System.IO.Path]::Combine($(MSBuildProjectDirectory), $(_RunWorkingDirectory))) + <_RuntimeConfigJsonPath>$([MSBuild]::NormalizePath($(_RunWorkingDirectory), '$(AssemblyName).runtimeconfig.json')) + exec "$([MSBuild]::NormalizePath($(WasmAppHostDir), 'WasmAppHost.dll'))" --use-staticwebassets --runtime-config "$(_RuntimeConfigJsonPath)" $(WasmHostArguments) - $(OutputPath) + $(_RunWorkingDirectory) diff --git a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs index 76a64c9fe4e76a..08488d487a6151 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs @@ -39,7 +39,7 @@ private void UpdateProgramCS() private void UpdateBrowserMainJs(string targetFramework, string runtimeAssetsRelativePath = DefaultRuntimeAssetsRelativePath) { - string mainJsPath = Path.Combine(_projectDir!, "main.js"); + string mainJsPath = Path.Combine(_projectDir!, "wwwroot", "main.js"); string mainJsContent = File.ReadAllText(mainJsPath); // .withExitOnUnhandledError() is available only only >net7.0 @@ -408,11 +408,12 @@ public void ConsolePublishAndRun(string config, bool aot, bool relinking) [Theory] [InlineData("", BuildTestBase.DefaultTargetFramework, DefaultRuntimeAssetsRelativePath)] - [InlineData("", BuildTestBase.DefaultTargetFramework, "./")] + // [ActiveIssue("https://github.com/dotnet/runtime/issues/90979")] + // [InlineData("", BuildTestBase.DefaultTargetFramework, "./")] + // [InlineData("-f net8.0", "net8.0", "./")] // [ActiveIssue("https://github.com/dotnet/runtime/issues/79313")] // [InlineData("-f net7.0", "net7.0")] [InlineData("-f net8.0", "net8.0", DefaultRuntimeAssetsRelativePath)] - [InlineData("-f net8.0", "net8.0", "./")] public async Task BrowserBuildAndRun(string extraNewArgs, string targetFramework, string runtimeAssetsRelativePath) { string config = "Debug"; diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs b/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs index 1f70aa46df8fa1..9ff2155c68e600 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs @@ -57,6 +57,21 @@ protected override IReadOnlySet GetDotNetFilesExpectedSet(AssertBundleOp return res; } + + public void AssertBundle(BuildArgs buildArgs, BuildProjectOptions buildProjectOptions) + { + AssertBundle(new( + Config: buildArgs.Config, + IsPublish: buildProjectOptions.Publish, + TargetFramework: buildProjectOptions.TargetFramework, + BinFrameworkDir: buildProjectOptions.BinFrameworkDir ?? FindBinFrameworkDir(buildArgs.Config, buildProjectOptions.Publish, buildProjectOptions.TargetFramework), + PredefinedIcudt: buildProjectOptions.PredefinedIcudt, + GlobalizationMode: buildProjectOptions.GlobalizationMode, + AssertSymbolsFile: false, + ExpectedFileType: buildProjectOptions.Publish && buildArgs.Config == "Release" ? NativeFilesType.Relinked : NativeFilesType.FromRuntimePack + )); + } + public void AssertBundle(AssertWasmSdkBundleOptions assertOptions) { IReadOnlyDictionary actualDotnetFiles = AssertBasicBundle(assertOptions); diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs index a76aaee38a929b..6280a022c1a424 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs @@ -59,19 +59,23 @@ public string CreateWasmTemplateProject(string id, string template = "wasmbrowse public (string projectDir, string buildOutput) BuildTemplateProject(BuildArgs buildArgs, string id, - BuildProjectOptions buildProjectOptions, - AssertTestMainJsAppBundleOptions? assertAppBundleOptions = null) + BuildProjectOptions buildProjectOptions) { (CommandResult res, string logFilePath) = BuildProjectWithoutAssert(id, buildArgs.Config, buildProjectOptions); if (buildProjectOptions.UseCache) _buildContext.CacheBuild(buildArgs, new BuildProduct(_projectDir!, logFilePath, true, res.Output)); if (buildProjectOptions.AssertAppBundle) - AssertBundle(buildArgs, buildProjectOptions, res.Output, assertAppBundleOptions); + { + if (buildProjectOptions.IsBrowserProject) + AssertWasmSdkBundle(buildArgs, buildProjectOptions, res.Output); + else + AssertTestMainJsBundle(buildArgs, buildProjectOptions, res.Output); + } return (_projectDir!, res.Output); } - public void AssertBundle(BuildArgs buildArgs, + public void AssertTestMainJsBundle(BuildArgs buildArgs, BuildProjectOptions buildProjectOptions, string? buildOutput = null, AssertTestMainJsAppBundleOptions? assertAppBundleOptions = null) @@ -79,11 +83,25 @@ public void AssertBundle(BuildArgs buildArgs, if (buildOutput is not null) ProjectProviderBase.AssertRuntimePackPath(buildOutput, buildProjectOptions.TargetFramework ?? DefaultTargetFramework); - // TODO: templates don't use wasm sdk yet var testMainJsProvider = new TestMainJsProjectProvider(_testOutput, _projectDir!); if (assertAppBundleOptions is not null) testMainJsProvider.AssertBundle(assertAppBundleOptions); else testMainJsProvider.AssertBundle(buildArgs, buildProjectOptions); } + + public void AssertWasmSdkBundle(BuildArgs buildArgs, + BuildProjectOptions buildProjectOptions, + string? buildOutput = null, + AssertWasmSdkBundleOptions? assertAppBundleOptions = null) + { + if (buildOutput is not null) + ProjectProviderBase.AssertRuntimePackPath(buildOutput, buildProjectOptions.TargetFramework ?? DefaultTargetFramework); + + var projectProvider = new WasmSdkBasedProjectProvider(_testOutput, _projectDir!); + if (assertAppBundleOptions is not null) + projectProvider.AssertBundle(assertAppBundleOptions); + else + projectProvider.AssertBundle(buildArgs, buildProjectOptions); + } } diff --git a/src/mono/wasm/host/BrowserHost.cs b/src/mono/wasm/host/BrowserHost.cs index 5c16a420e76deb..adb24f81f88dac 100644 --- a/src/mono/wasm/host/BrowserHost.cs +++ b/src/mono/wasm/host/BrowserHost.cs @@ -167,7 +167,7 @@ private static DevServerOptions CreateDevServerOptions(BrowserArguments args, st devServerOptions = CreateDevServerOptions(urls, staticWebAssetsPath, onConsoleConnected); if (devServerOptions == null) - throw new CommandLineException("Please, provide mainAssembly in hostProperties of runtimeconfig"); + throw new CommandLineException($"Please, provide mainAssembly in hostProperties of runtimeconfig. Alternatively leave the static web assets manifest ('*{staticWebAssetsV2Extension}') in the build output directory '{appPath}' ."); } return devServerOptions; @@ -183,7 +183,7 @@ private static DevServerOptions CreateDevServerOptions(BrowserArguments args, st ); private static string? FindFirstFileWithExtension(string directory, string extension) - => Directory.EnumerateFiles(directory, "*" + extension).First(); + => Directory.EnumerateFiles(directory, "*" + extension).FirstOrDefault(); private async Task RunConsoleMessagesPump(WebSocket socket, WasmTestMessagesProcessor messagesProcessor, CancellationToken token) { diff --git a/src/mono/wasm/host/DevServer/DevServer.cs b/src/mono/wasm/host/DevServer/DevServer.cs index b1369deabcc0cc..1acbe6954eeb3b 100644 --- a/src/mono/wasm/host/DevServer/DevServer.cs +++ b/src/mono/wasm/host/DevServer/DevServer.cs @@ -70,8 +70,7 @@ private static IConfiguration ConfigureHostConfiguration(DevServerOptions option [WebHostDefaults.EnvironmentKey] = "Development", ["Logging:LogLevel:Microsoft"] = "Warning", ["Logging:LogLevel:Microsoft.Hosting.Lifetime"] = "Information", - [WebHostDefaults.StaticWebAssetsKey] = options.StaticWebAssetsPath, - ["ApplyCopHeaders"] = options.WebServerUseCrossOriginPolicy.ToString() + [WebHostDefaults.StaticWebAssetsKey] = options.StaticWebAssetsPath }; config.AddInMemoryCollection(inMemoryConfiguration); diff --git a/src/mono/wasm/host/DevServer/DevServerStartup.cs b/src/mono/wasm/host/DevServer/DevServerStartup.cs index f438caf4b4b7ae..0fdc45a1754fdf 100644 --- a/src/mono/wasm/host/DevServer/DevServerStartup.cs +++ b/src/mono/wasm/host/DevServer/DevServerStartup.cs @@ -2,13 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Net.WebSockets; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.WebAssembly.AppHost; namespace Microsoft.WebAssembly.AppHost.DevServer; @@ -27,16 +30,16 @@ public static void ConfigureServices(IServiceCollection services) services.AddRouting(); } - public static void Configure(IApplicationBuilder app, TaskCompletionSource realUrlsAvailableTcs, ILogger logger, IHostApplicationLifetime applicationLifetime, IConfiguration configuration) + public static void Configure(IApplicationBuilder app, IOptions optionsContainer, TaskCompletionSource realUrlsAvailableTcs, ILogger logger, IHostApplicationLifetime applicationLifetime, IConfiguration configuration) { app.UseDeveloperExceptionPage(); EnableConfiguredPathbase(app, configuration); app.UseWebAssemblyDebugging(); - bool applyCopHeaders = configuration.GetValue("ApplyCopHeaders"); + DevServerOptions options = optionsContainer.Value; - if (applyCopHeaders) + if (options.WebServerUseCrossOriginPolicy) { app.Use(async (ctx, next) => { @@ -63,6 +66,29 @@ public static void Configure(IApplicationBuilder app, TaskCompletionSource + { + if (ctx.Request.Path.StartsWithSegments("/console")) + { + if (!ctx.WebSockets.IsWebSocketRequest) + { + ctx.Response.StatusCode = 400; + return; + } + + using WebSocket socket = await ctx.WebSockets.AcceptWebSocketAsync(); + await options.OnConsoleConnected(socket); + } + else + { + await next(ctx); + } + }); + } app.UseEndpoints(endpoints => { @@ -70,7 +96,7 @@ public static void Configure(IApplicationBuilder app, TaskCompletionSource { - if (applyCopHeaders) + if (options.WebServerUseCrossOriginPolicy) { // Browser multi-threaded runtime requires cross-origin policy headers to enable SharedArrayBuffer. ApplyCrossOriginPolicyHeaders(fileContext.Context); diff --git a/src/mono/wasm/host/Program.cs b/src/mono/wasm/host/Program.cs index a5005dce9d0fc4..105eb59929ecab 100644 --- a/src/mono/wasm/host/Program.cs +++ b/src/mono/wasm/host/Program.cs @@ -30,6 +30,9 @@ public static async Task Main(string[] args) RegisterHostHandler(WasmHost.Wasmtime, WasiEngineHost.InvokeAsync); using CancellationTokenSource cts = new(); + + Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel(); + ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder .AddPassThroughConsole() diff --git a/src/mono/wasm/templates/templates/browser/README.md b/src/mono/wasm/templates/templates/browser/README.md deleted file mode 100644 index 7ddf4fd1bce9bd..00000000000000 --- a/src/mono/wasm/templates/templates/browser/README.md +++ /dev/null @@ -1,26 +0,0 @@ -## .NET WebAssembly Browser app - -## Build - -You can build the app from Visual Studio or from the command-line: - -``` -dotnet build -c Debug/Release -``` - -After building the app, the result is in the `bin/$(Configuration)/net7.0/browser-wasm/AppBundle` directory. - -## Run - -You can build the app from Visual Studio or the command-line: - -``` -dotnet run -c Debug/Release -``` - -Or you can start any static file server from the AppBundle directory: - -``` -dotnet tool install dotnet-serve -dotnet serve -d:bin/$(Configuration)/net7.0/browser-wasm/AppBundle -``` \ No newline at end of file diff --git a/src/mono/wasm/templates/templates/browser/browser.0.csproj b/src/mono/wasm/templates/templates/browser/browser.0.csproj index 401bdae24fab86..588c5219582125 100644 --- a/src/mono/wasm/templates/templates/browser/browser.0.csproj +++ b/src/mono/wasm/templates/templates/browser/browser.0.csproj @@ -1,13 +1,6 @@ - + - net7.0 - browser-wasm - Exe + net8.0 true - - - - - diff --git a/src/mono/wasm/templates/templates/browser/runtimeconfig.template.json b/src/mono/wasm/templates/templates/browser/runtimeconfig.template.json index 8f0557352c6ed3..b96a94320ba5ee 100644 --- a/src/mono/wasm/templates/templates/browser/runtimeconfig.template.json +++ b/src/mono/wasm/templates/templates/browser/runtimeconfig.template.json @@ -3,9 +3,8 @@ "perHostConfig": [ { "name": "browser", - "html-path": "index.html", - "Host": "browser" + "host": "browser" } ] } -} +} \ No newline at end of file diff --git a/src/mono/wasm/templates/templates/browser/index.html b/src/mono/wasm/templates/templates/browser/wwwroot/index.html similarity index 100% rename from src/mono/wasm/templates/templates/browser/index.html rename to src/mono/wasm/templates/templates/browser/wwwroot/index.html diff --git a/src/mono/wasm/templates/templates/browser/main.js b/src/mono/wasm/templates/templates/browser/wwwroot/main.js similarity index 100% rename from src/mono/wasm/templates/templates/browser/main.js rename to src/mono/wasm/templates/templates/browser/wwwroot/main.js From f841e210743e4ffe623bdc07084d3fd3cc770d69 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 12:43:55 -0700 Subject: [PATCH 110/345] Update dependencies from https://github.com/dotnet/arcade build 20230829.1 (#91329) Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23428.2 -> To Version 8.0.0-beta.23429.1 Dependency coherency updates Microsoft.DotNet.XliffTasks From Version 1.0.0-beta.23423.1 -> To Version 1.0.0-beta.23426.1 (parent: Microsoft.DotNet.Arcade.Sdk Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 76 ++++++++++++++++++++--------------------- eng/Versions.props | 30 ++++++++-------- global.json | 6 ++-- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index efb4b40dceea8c..c60d708a560fa2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -107,79 +107,79 @@ - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/xliff-tasks - ed9a83526483c094fb51e7000b6f816ce6cb0325 + 194f32828726c3f1f63f79f3dc09b9e99c157b11 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 https://github.com/dotnet/runtime-assets @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 3d92d0bfd8c9006f5fe1687e465dc4f8aa068b00 + 804d586c07a6c598551a2913f0958680cb9135a9 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 6b31387aabe99d..f6df5c7fdd62e8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,21 +85,21 @@ 8.0.100-preview.7.23329.3 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 2.5.1-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 - 8.0.0-beta.23428.2 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 2.5.1-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 + 8.0.0-beta.23429.1 6.0.0-preview.1.102 diff --git a/global.json b/global.json index fd45afe4dd2784..bdd818850a3add 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23428.2", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23428.2", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23428.2", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23429.1", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23429.1", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23429.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From a02c66044abbb4f4d9db87ebc370f78ba084b945 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 12:47:43 -0700 Subject: [PATCH 111/345] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230829.4 (#91330) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23427.2 -> To Version 1.0.0-prerelease.23429.4 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c60d708a560fa2..e2026ba5907ba6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 804d586c07a6c598551a2913f0958680cb9135a9 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ffa66bdcbd319c11795d23e835e7a44344723332 + 1d8fc814dda596c04d571122ce984f45f92c56f8 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ffa66bdcbd319c11795d23e835e7a44344723332 + 1d8fc814dda596c04d571122ce984f45f92c56f8 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ffa66bdcbd319c11795d23e835e7a44344723332 + 1d8fc814dda596c04d571122ce984f45f92c56f8 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ffa66bdcbd319c11795d23e835e7a44344723332 + 1d8fc814dda596c04d571122ce984f45f92c56f8 https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ffa66bdcbd319c11795d23e835e7a44344723332 + 1d8fc814dda596c04d571122ce984f45f92c56f8 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ffa66bdcbd319c11795d23e835e7a44344723332 + 1d8fc814dda596c04d571122ce984f45f92c56f8 diff --git a/eng/Versions.props b/eng/Versions.props index f6df5c7fdd62e8..8234d10cc507cc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23427.2 - 1.0.0-prerelease.23427.2 - 1.0.0-prerelease.23427.2 - 1.0.0-prerelease.23427.2 - 1.0.0-prerelease.23427.2 - 1.0.0-prerelease.23427.2 + 1.0.0-prerelease.23429.4 + 1.0.0-prerelease.23429.4 + 1.0.0-prerelease.23429.4 + 1.0.0-prerelease.23429.4 + 1.0.0-prerelease.23429.4 + 1.0.0-prerelease.23429.4 16.11.27-beta1.23180.1 2.0.0-beta4.23307.1 From 592e01f5619a21e331d8b1fcf129f05cf8626816 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 12:48:03 -0700 Subject: [PATCH 112/345] Ensure the relevant containable nodes are handled (#91334) Co-authored-by: Tanner Gooding --- src/coreclr/jit/lowerxarch.cpp | 16 +++++ .../JitBlue/Runtime_91170/Runtime_91170.cs | 63 +++++++++++++++++++ .../Runtime_91170/Runtime_91170.csproj | 8 +++ 3 files changed, 87 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.csproj diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index c1b5079f124545..00143839a440d7 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -8135,7 +8135,16 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre case NI_Vector128_ToScalar: case NI_Vector256_ToScalar: case NI_Vector512_ToScalar: + case NI_SSE2_ConvertToInt32: + case NI_SSE2_ConvertToUInt32: + case NI_SSE2_X64_ConvertToInt64: + case NI_SSE2_X64_ConvertToUInt64: + case NI_SSE2_Extract: + case NI_SSE41_Extract: + case NI_SSE41_X64_Extract: case NI_AVX_ExtractVector128: + case NI_AVX2_ConvertToInt32: + case NI_AVX2_ConvertToUInt32: case NI_AVX2_ExtractVector128: case NI_AVX512F_ExtractVector128: case NI_AVX512F_ExtractVector256: @@ -8178,6 +8187,13 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre return false; } + case NI_Vector128_get_Zero: + case NI_Vector256_get_Zero: + { + // These are only containable as part of Sse41.Insert + return false; + } + case NI_SSE3_MoveAndDuplicate: case NI_AVX2_BroadcastScalarToVector128: case NI_AVX2_BroadcastScalarToVector256: diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs new file mode 100644 index 00000000000000..afb26b6def0bc0 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license.aa + +// Found by Antigen + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using System.Numerics; +using Xunit; + +public class TestClass +{ + public struct S1 + { + } + + static short s_short_8 = 5; + static int s_int_9 = -2; + long long_59 = 4; + uint uint_64 = 1; + Vector256 v256_int_90 = Vector256.Create(2, -5, 4, 4, 5, 0, -1, 5); + S1 s1_99 = new S1(); + + private uint Method4(out short p_short_161, S1 p_s1_162, bool p_bool_163, ref int p_int_164) + { + unchecked + { + p_short_161 = 15|4; + if ((long_59 *= 15>>4)!= (long_59 |= 15^4)) + { + } + else + { + Vector128.CreateScalarUnsafe(Vector256.Sum(v256_int_90)); + } + return 15|4; + } + } + + private void Method0() + { + unchecked + { + uint_64 = Method4(out s_short_8, s1_99, 15<4, ref s_int_9); + return; + } + } + + [Fact] + public static void TestEntryPoint() + { + new TestClass().Method0(); + } +} +/* + +Assert failure(PID 34336 [0x00008620], Thread: 38576 [0x96b0]): Assertion failed '!childNode->isContainableHWIntrinsic()' in 'TestClass:Method4(byref,TestClass+S1,bool,byref):uint:this' during 'Lowering nodeinfo' (IL size 63; hash 0xa4e6dede; Tier0) + File: D:\git\runtime\src\coreclr\jit\lowerxarch.cpp Line: 8201 + Image: D:\git\runtime\artifacts\tests\coreclr\windows.x64.Checked\tests\Core_Root\CoreRun.exe +*/ diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 8ec6101174f841ec455180fba8f08d895e76ef2a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:06:02 -0700 Subject: [PATCH 113/345] [release/8.0] Emit interceptor info correctly when invocation expr is on separate line (#91218) * Emit interceptor info correctly when invocation expr is on separate line * Add more tests and add helper to udpate baselines * Add comments to binding gen tests for invocations on new lines (#91237) * Add comments to binding gen tests for invocations on new lines * Address feedback & test static method call syntax * Reorganize and comment the newline/whitespace scenarios * Reorganize and comment the newline/whitespace scenarios for ConfigurationExtensions --------- Co-authored-by: Jeff Handley * Update baselines --------- Co-authored-by: Layomi Akinrinade Co-authored-by: Jeff Handley --- ...onfigurationServiceCollectionExtensions.cs | 2 +- .../gen/Helpers/InterceptorLocationInfo.cs | 35 ++- .../ConfigurationBinderTests.Helpers.cs | 12 + .../ConfigurationBinderTests.TestClasses.cs | 12 - .../OptionsBuilder/Bind_T.generated.txt | 2 +- .../Bind_T_BinderOptions.generated.txt | 2 +- .../Configure_T.generated.txt | 2 +- .../Configure_T_BinderOptions.generated.txt | 2 +- .../Configure_T_name.generated.txt | 2 +- ...nfigure_T_name_BinderOptions.generated.txt | 2 +- .../ConfigurationBinderTests.Generator.cs | 253 ++++++++++++++++++ ...cs => GeneratorTests.Baselines.Options.cs} | 2 +- ...selines.cs => GeneratorTests.Baselines.cs} | 3 +- ...ingGeneratorTests.cs => GeneratorTests.cs} | 22 +- ...ation.Binder.SourceGeneration.Tests.csproj | 9 +- .../Common/ConfigurationExtensionsTests.cs | 21 ++ ...ionsBuilderConfigurationExtensionsTests.cs | 7 +- .../ConfigurationExtensionsTest.Generator.cs | 160 +++++++++++ ...onExtensions.SourceGeneration.Tests.csproj | 4 +- 19 files changed, 502 insertions(+), 52 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/{ConfigurationBindingGeneratorTests.Baselines.Options.cs => GeneratorTests.Baselines.Options.cs} (98%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/{ConfigurationBindingGeneratorTests.Baselines.cs => GeneratorTests.Baselines.cs} (99%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/{ConfigurationBindingGeneratorTests.cs => GeneratorTests.cs} (94%) create mode 100644 src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs create mode 100644 src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs index 0348eb5047e970..41eeb8b657342d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs @@ -62,7 +62,7 @@ private void EmitConfigureMethods() _writer.WriteLine($$""" OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}}); {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}})); - return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}){{Identifier.configureOptions}}))); + return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}))); """); EmitEndBlock(); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs index d1dc4f4afa7e7e..441acbe6a7444f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs @@ -15,28 +15,27 @@ internal sealed record InterceptorLocationInfo { public InterceptorLocationInfo(IInvocationOperation operation) { - SyntaxNode operationSyntax = operation.Syntax; - TextSpan operationSpan = operationSyntax.Span; - SyntaxTree operationSyntaxTree = operationSyntax.SyntaxTree; - - FilePath = GetInterceptorFilePath(operationSyntaxTree, operation.SemanticModel?.Compilation.Options.SourceReferenceResolver); - - FileLinePositionSpan span = operationSyntaxTree.GetLineSpan(operationSpan); - LineNumber = span.StartLinePosition.Line + 1; - - // Calculate the character offset to the end of the binding invocation detected. - int invocationLength = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operationSyntax).Expression).Expression.Span.Length; - CharacterNumber = span.StartLinePosition.Character + invocationLength + 2; + MemberAccessExpressionSyntax memberAccessExprSyntax = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operation.Syntax).Expression); + SyntaxTree operationSyntaxTree = operation.Syntax.SyntaxTree; + TextSpan memberNameSpan = memberAccessExprSyntax.Name.Span; + FileLinePositionSpan linePosSpan = operationSyntaxTree.GetLineSpan(memberNameSpan); + + LineNumber = linePosSpan.StartLinePosition.Line + 1; + CharacterNumber = linePosSpan.StartLinePosition.Character + 1; + FilePath = GetInterceptorFilePath(); + + // Use the same logic used by the interceptors API for resolving the source mapped value of a path. + // https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064 + string GetInterceptorFilePath() + { + SourceReferenceResolver? sourceReferenceResolver = operation.SemanticModel?.Compilation.Options.SourceReferenceResolver; + return sourceReferenceResolver?.NormalizePath(operationSyntaxTree.FilePath, baseFilePath: null) ?? operationSyntaxTree.FilePath; + } } public string FilePath { get; } public int LineNumber { get; } public int CharacterNumber { get; } - - // Utilize the same logic used by the interceptors API for resolving the source mapped value of a path. - // https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064 - private static string GetInterceptorFilePath(SyntaxTree tree, SourceReferenceResolver? resolver) => - resolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath; } internal sealed record ConfigurationBinderInterceptorInfo @@ -52,7 +51,7 @@ public void RegisterOverloadInfo(MethodsToGen_ConfigurationBinder overload, Type } public OverloadInterceptorInfo GetOverloadInfo(MethodsToGen_ConfigurationBinder overload) => - DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentNullException(nameof(overload)); + DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentOutOfRangeException(nameof(overload)); private OverloadInterceptorInfo? DetermineOverload(MethodsToGen_ConfigurationBinder overload, bool initIfNull) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs index a1d1a72ffab20f..d6521ed86dfdec 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs @@ -160,5 +160,17 @@ public class CustomICollectionWithoutAnAddMethod : ICollection public int Count => _items.Count; public bool IsReadOnly => false; } + + public interface IGeolocation + { + public double Latitude { get; set; } + public double Longitude { get; set; } + } + + public sealed record GeolocationRecord : IGeolocation + { + public double Latitude { get; set; } + public double Longitude { get; set; } + } #endregion } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs index 1e537b407963d9..76ed9d959e6220 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs @@ -667,12 +667,6 @@ public struct StructWithParameterlessAndParameterizedCtor public int MyInt { get; } } - public interface IGeolocation - { - public double Latitude { get; set; } - public double Longitude { get; set; } - } - [TypeConverter(typeof(GeolocationTypeConverter))] public struct Geolocation : IGeolocation { @@ -704,12 +698,6 @@ public sealed class GeolocationClass : IGeolocation public double Longitude { get; set; } } - public sealed record GeolocationRecord : IGeolocation - { - public double Latitude { get; set; } - public double Longitude { get; set; } - } - public class GeolocationWrapper { public Geolocation Location { get; set; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index 633196e7a742d5..ff590d8398f3a1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -68,7 +68,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index fb5b4b4ad721d8..b7b6ef86a4c056 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -62,7 +62,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 7f626f0e27c527..7a956f99b57b13 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index 5848c2412f9b78..399f6ffe35b935 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index 91226d730166f1..197e268561f7eb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -53,7 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 8c9ccaa71a779f..0cb5881950dee3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -47,7 +47,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs new file mode 100644 index 00000000000000..0e4a97b85b548a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs @@ -0,0 +1,253 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Configuration; +using Xunit; + +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests +{ + public partial class ConfigurationBinderTests : ConfigurationBinderTestsBase + { + // These are regression tests for https://github.com/dotnet/runtime/issues/90851 + // Source Generator Interceptors rely on identifying an accurate invocation + // source location (line and character positions). These tests cover newline + // and whitespace scenarios to ensure the interceptors get wired up correctly. + + [Fact] + public void TestBindingInvocationsWithNewlines_GetMethodTypeArg() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); + + // Newline between the configuration instance and the binding invocation (with the dot on the first line) + GeolocationRecord record1 = (GeolocationRecord)configuration. + Get(typeof(GeolocationRecord), _ => { }); + + AssertRecordIsBound(record1, 1, 2); + + // Newline between the configuration instance and the binding invocation (with the dot on the second line) + GeolocationRecord record2 = (GeolocationRecord)configuration + .Get(typeof(GeolocationRecord), _ => { }); + + AssertRecordIsBound(record2, 1, 2); + + // Newlines between the instance, the invocation, and the arguments + GeolocationRecord record3 = (GeolocationRecord)configuration + .Get( + typeof(GeolocationRecord), + _ => { } + ); + + AssertRecordIsBound(record3, 1, 2); + + // Newlines before and after the instance (with the dot on the first line) + GeolocationRecord record4 = (GeolocationRecord) + configuration. + Get(typeof(GeolocationRecord), _ => { }); + + AssertRecordIsBound(record4, 1, 2); + + // Newlines before and after the instance (with the dot on the second line) + GeolocationRecord record5 = (GeolocationRecord) + configuration + .Get(typeof(GeolocationRecord), _ => { }); + + AssertRecordIsBound(record5, 1, 2); + + // Newlines in every place possible + GeolocationRecord + record6 + = + ( + GeolocationRecord + ) + configuration + . + Get + ( + typeof + ( + GeolocationRecord + ) + , + _ + => + { + } + ) + ; + + AssertRecordIsBound(record6, 1, 2); + } + + [Fact] + public void TestBindingInvocationsWithNewlines_GetMethodGeneric() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); + + // Newline between the invocation method name and the generic type argument + GeolocationRecord record1 = configuration.Get + (); + + AssertRecordIsBound(record1, 1, 2); + + // Newlines on either side of the generic type argument + GeolocationRecord record2 = configuration.Get< + GeolocationRecord + >(); + + AssertRecordIsBound(record2, 1, 2); + + // Newlines in every place possible + GeolocationRecord + record3 + = + configuration + . + Get + < + GeolocationRecord + > + () + ; + + AssertRecordIsBound(record3, 1, 2); + } + + [Fact] + public void TestBindingInvocationsWithNewlines_BindExtensionMethod() + { + // Newline between the configuration instance and the extension method invocation + GeolocationRecord record1 = new GeolocationRecord(); + TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}") + .Bind(record1); + + AssertRecordIsBound(record1, 1, 2); + + // Newlines between the method that returns the instance and the extension method invocation + GeolocationRecord record2 = new GeolocationRecord(); + TestHelpers + .GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}") + .Bind(record2); + + AssertRecordIsBound(record2, 1, 2); + + // Newlines within the argument to the method returning the configuration and around the extension method argument + GeolocationRecord record3 = new GeolocationRecord(); + TestHelpers + .GetConfigurationFromJsonString(@"{""Longitude"":1, + ""Latitude"":2} + ") + .Bind( + record3 + ); + + AssertRecordIsBound(record3, 1, 2); + + // Newlines in every place possible + GeolocationRecord record4 = new GeolocationRecord(); + TestHelpers + . + GetConfigurationFromJsonString + ( + @"{""Longitude"":1, ""Latitude"":2}" + ) + . + Bind + ( + record4 + ) + ; + + AssertRecordIsBound(record4, 1, 2); + } + + [Fact] + public void TestBindingInvocationsWithNewlines_BindStaticMethod() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); + + // Newline between the class and the static method invocation (with the dot on the first line) + GeolocationRecord record1 = new GeolocationRecord(); + ConfigurationBinder. + Bind(configuration, record1); + + // Newline between the class and the static method invocation (with the dot on the second line) + GeolocationRecord record2 = new GeolocationRecord(); + ConfigurationBinder + .Bind(configuration, record2); + + AssertRecordIsBound(record2, 1, 2); + + // Newline before the arguments + GeolocationRecord record3 = new GeolocationRecord(); + ConfigurationBinder.Bind( + configuration, record3); + + AssertRecordIsBound(record3, 1, 2); + + // Newlines in every place possible + GeolocationRecord record4 = new GeolocationRecord(); + ConfigurationBinder + . + Bind + ( + configuration + , + record4 + ) + ; + + AssertRecordIsBound(record4, 1, 2); + } + + [Fact] + public void TestBindingInvocationsWithNewlines_GetValueMethod() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); + + // Newline between the configuration instance and the binding invocation (with the dot on the first line) + int lat1 = configuration. + GetValue("Latitude"); + + Assert.Equal(2, lat1); + + // Newline between the configuration instance and the binding invocation (with the dot on the second line) + int lat2 = configuration + .GetValue("Latitude"); + + Assert.Equal(2, lat2); + + // Newlines in every place possible + long + lat3 + = + configuration + . + GetValue + < + int + > + ( + "Latitude" + ) + ; + Assert.Equal(2, lat3); + + // Newlines and pragmas wrapped around the generic type argument + long lat4 = configuration.GetValue< +#if DEBUG + int +#else + long +#endif + >("Latitude"); + + Assert.Equal(2, lat4); + } + + private static void AssertRecordIsBound(GeolocationRecord record, int longitude, int latitude) + { + Assert.Equal((longitude, latitude), (record.Longitude, record.Latitude)); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs similarity index 98% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index c9eb9c70927f99..0126744eacbfa4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Xunit; -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { public partial class ConfigurationBindingGeneratorTests { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs similarity index 99% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index b5c3fb49c5e7eb..65e812d30b420f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -8,7 +8,7 @@ using Microsoft.CodeAnalysis.CSharp; using Xunit; -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { public partial class ConfigurationBindingGeneratorTests { @@ -649,7 +649,6 @@ public interface ICustomSet : ISet await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => { - Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count())); Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); }); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs similarity index 94% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index a512c5efe495b1..68f8a66612e67f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBindingGeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -14,13 +14,14 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Binder.SourceGeneration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests; using SourceGenerators.Tests; using Xunit; -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase @@ -388,11 +389,24 @@ private static async Task VerifyAgainstBaselineUsingFile( var (d, r) = await RunGenerator(testSourceCode, languageVersion); bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); -#if !SKIP_BASELINES +#if UPDATE_BASELINES + if (!success) + { + string? repoRootDir = Environment.GetEnvironmentVariable("RepoRootDir"); + Assert.True(repoRootDir is not null, "To update baselines, specifiy the root runtime repo dir"); + + IEnumerable lines = r[0].SourceText.Lines.Select(l => l.ToString()); + string source = string.Join(Environment.NewLine, lines).TrimEnd(Environment.NewLine.ToCharArray()) + Environment.NewLine; + path = Path.Combine($"{repoRootDir}\\src\\libraries\\Microsoft.Extensions.Configuration.Binder\\tests\\SourceGenerationTests\\", path); + + await File.WriteAllTextAsync(path, source).ConfigureAwait(false); + success = true; + } +#endif + Assert.Single(r); (assessDiagnostics ?? ((d) => Assert.Empty(d))).Invoke(d); Assert.True(success, errorMessage); -#endif } private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index cfd45c365d42a0..94d95564a47352 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -11,7 +11,7 @@ $(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER $(DefineConstants);LAUNCH_DEBUGGER - $(DefineConstants);SKIP_BASELINES + $(DefineConstants);UPDATE_BASELINES @@ -28,6 +28,7 @@ + @@ -50,9 +51,9 @@ PreserveNewest - - - + + + diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs new file mode 100644 index 00000000000000..95cee559072f07 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.Extensions.Options.ConfigurationExtensions.Tests +{ + public partial class ConfigurationExtensionsTests + { + private static IConfiguration s_emptyConfig { get; } = new ConfigurationBuilder().Build(); + + private static OptionsBuilder CreateOptionsBuilder() + { + var services = new ServiceCollection(); + return new OptionsBuilder(services, Options.DefaultName); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/OptionsBuilderConfigurationExtensionsTests.cs b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/OptionsBuilderConfigurationExtensionsTests.cs index 6d1d4a018f097e..d90122ef74d8bc 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/OptionsBuilderConfigurationExtensionsTests.cs +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/OptionsBuilderConfigurationExtensionsTests.cs @@ -31,7 +31,8 @@ public static void BindConfiguration_ThrowsForNullConfigurationSectionPath() Assert.Throws("configSectionPath", () => { - optionsBuilder.BindConfiguration(configSectionPath); + optionsBuilder + .BindConfiguration(configSectionPath); }); } @@ -170,8 +171,8 @@ public static void BindConfiguration_UpdatesOptionOnConfigurationUpdate() services.AddSingleton(new ConfigurationBuilder() .Add(configSource) .Build()); - OptionsBuilder optionsBuilder = services.AddOptions(); - _ = optionsBuilder.BindConfiguration(configSectionName); + _ = services.AddOptions() + .BindConfiguration(configSectionName); using ServiceProvider serviceProvider = services.BuildServiceProvider(); var optionsMonitor = serviceProvider.GetRequiredService>(); bool updateHasRun = false; diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs new file mode 100644 index 00000000000000..a18efc6909b71d --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs @@ -0,0 +1,160 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace Microsoft.Extensions.Options.ConfigurationExtensions.Tests +{ + public partial class ConfigurationExtensionsTests + { + // These are regression tests for https://github.com/dotnet/runtime/issues/90851 + // Source Generator Interceptors rely on identifying an accurate invocation + // source location (line and character positions). These tests cover newline + // and whitespace scenarios to ensure the interceptors get wired up correctly. + + [Fact] + public void TestBindingInvocationsWithNewlines_BindExtension() + { + OptionsBuilder? optionsBuilder = CreateOptionsBuilder(); + + // Newline between instance and invocation using configureBinder argument (with the dot on the first line) + optionsBuilder. + Bind(s_emptyConfig, configureBinder: null); + + // Newline between instance and invocation using configureBinder argument (with the dot on the second line) + optionsBuilder + .Bind(s_emptyConfig, configureBinder: null); + + // Newline between instance and invocation (with the dot on the first line) + optionsBuilder. + Bind(s_emptyConfig); + + // Newline between instance and invocation (with the dot on the second line) + optionsBuilder + .Bind(s_emptyConfig); + + // Newlines in every place possible + optionsBuilder + . + Bind + ( + s_emptyConfig + , + configureBinder + : + null + ) + ; + } + + [Fact] + public void TestBindingInvocationsWithNewlines_BindConfigurationExtension() + { + OptionsBuilder? optionsBuilder = CreateOptionsBuilder(); + + // Newline between instance and invocation using configureBinder argument (with the dot on the first line) + optionsBuilder. + BindConfiguration(configSectionPath: "path", + _ => { }); + + // Newline between instance and invocation using configureBinder argument (with the dot on the second line) + optionsBuilder + .BindConfiguration(configSectionPath: "path", + _ => { }); + + // Newlines between the instance and invocation and within the arguments. No indentation before invocation. + optionsBuilder. + BindConfiguration( + configSectionPath: "path", + _ => { }); + + // Newlines in every place possible + optionsBuilder + . + BindConfiguration + ( + configSectionPath + : + "path" + , + _ + => + { + } + ) + ; + } + + [Fact] + public void TestBindingInvocationsWithNewlines_ConfigureExtension() + { + OptionsBuilder? optionsBuilder = CreateOptionsBuilder(); + IServiceCollection services = new ServiceCollection(); + + // Newlines between each method call + services + .Configure(s_emptyConfig) + .AddOptions(); + + // Newlines in every place possible + services + . + Configure + < + FakeOptions + > + ( + name + : + null! + , + s_emptyConfig + ) + ; + } + + [Fact] + public void TestBindingInvocationsWithNewlines_StaticCalls() + { + OptionsBuilder? optionsBuilder = CreateOptionsBuilder(); + IServiceCollection services = new ServiceCollection(); + + // Bind: Newlines in every place possible + OptionsBuilderConfigurationExtensions + . + Bind + ( + optionsBuilder + , + s_emptyConfig + ) + ; + + // // BindConfiguration: Newlines in every place possible + OptionsBuilderConfigurationExtensions + . + BindConfiguration + ( + optionsBuilder + , + "path" + ); + + // Configure: Newlines in every place possible + OptionsConfigurationServiceCollectionExtensions + . + Configure + < + FakeOptions + > + ( + services + , + s_emptyConfig + ) + ; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj index 0676fddc289826..f08d2bd649bc3f 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj @@ -20,10 +20,12 @@ + - + + From 71740922153cdfab9f853a8deb6357eac3172561 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:07:02 -0700 Subject: [PATCH 114/345] [release/8.0] Fix crash when calling AssemblyLoadContext.Unload twice (#91346) * Fix crash when calling AssemblyLoadContext.Unload twice The AssemblyLoadContext.InitiateUnload method was not handling multiple calls correctly. Instead of making the extra calls dummy, it was calling the native runtime helper again. This change fixes it by simply ensuring that the runtime helper is called just once. * Add regression test --------- Co-authored-by: Jan Vorlicek --- .../Runtime/Loader/AssemblyLoadContext.cs | 29 ++++++++++++------- .../CollectibleAssemblyLoadContextTest.cs | 19 +++++++++++- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs index b8b4ba086ad69b..59123e42fb52a2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -135,25 +135,32 @@ private void InitiateUnload() { RaiseUnloadEvent(); + InternalState previousState; + // When in Unloading state, we are not supposed to be called on the finalizer // as the native side is holding a strong reference after calling Unload lock (_unloadLock) { - Debug.Assert(_state == InternalState.Alive); - - var thisStrongHandle = GCHandle.Alloc(this, GCHandleType.Normal); - var thisStrongHandlePtr = GCHandle.ToIntPtr(thisStrongHandle); - // The underlying code will transform the original weak handle - // created by InitializeLoadContext to a strong handle - PrepareForAssemblyLoadContextRelease(_nativeAssemblyLoadContext, thisStrongHandlePtr); + previousState = _state; + if (previousState == InternalState.Alive) + { + var thisStrongHandle = GCHandle.Alloc(this, GCHandleType.Normal); + var thisStrongHandlePtr = GCHandle.ToIntPtr(thisStrongHandle); + // The underlying code will transform the original weak handle + // created by InitializeLoadContext to a strong handle + PrepareForAssemblyLoadContextRelease(_nativeAssemblyLoadContext, thisStrongHandlePtr); - _state = InternalState.Unloading; + _state = InternalState.Unloading; + } } - Dictionary> allContexts = AllContexts; - lock (allContexts) + if (previousState == InternalState.Alive) { - allContexts.Remove(_id); + Dictionary> allContexts = AllContexts; + lock (allContexts) + { + allContexts.Remove(_id); + } } } diff --git a/src/libraries/System.Runtime.Loader/tests/CollectibleAssemblyLoadContextTest.cs b/src/libraries/System.Runtime.Loader/tests/CollectibleAssemblyLoadContextTest.cs index 90527c3d0be9de..83d1c9aebf61f7 100644 --- a/src/libraries/System.Runtime.Loader/tests/CollectibleAssemblyLoadContextTest.cs +++ b/src/libraries/System.Runtime.Loader/tests/CollectibleAssemblyLoadContextTest.cs @@ -16,12 +16,16 @@ public partial class AssemblyLoadContextTest // Tests related to Collectible assemblies [MethodImpl(MethodImplOptions.NoInlining)] - static void CreateAndLoadContext(CollectibleChecker checker) + static void CreateAndLoadContext(CollectibleChecker checker, bool unloadTwice = false) { var alc = new ResourceAssemblyLoadContext(true); checker.SetAssemblyLoadContext(0, alc); alc.Unload(); + if (unloadTwice) + { + alc.Unload(); + } // Check that any attempt to load an assembly after an explicit Unload will fail Assert.Throws(() => alc.LoadFromAssemblyPath(Path.GetFullPath("none.dll"))); @@ -39,6 +43,19 @@ public static void Unload_CollectibleWithNoAssemblyLoaded() checker.GcAndCheck(); } + [Fact] + [ActiveIssue("https://github.com/mono/mono/issues/15142", TestRuntimes.Mono)] + public static void DoubleUnload_CollectibleWithNoAssemblyLoaded() + { + // Use a collectible ALC + Unload + // Check that we receive the Unloading event + + var checker = new CollectibleChecker(1); + CreateAndLoadContext(checker, unloadTwice: true); + checker.GcAndCheck(); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))] public static void Finalizer_CollectibleWithNoAssemblyLoaded() { From 41b2c8f8f50e87efa9c2e5435d87fe550631ec44 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 30 Aug 2023 14:07:16 -0700 Subject: [PATCH 115/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2256251 (#91347) * Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2256251 * Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2256251 --- .../gen/Resources/xlf/Strings.cs.xlf | 4 ++-- .../gen/Resources/xlf/Strings.de.xlf | 4 ++-- .../gen/Resources/xlf/Strings.es.xlf | 4 ++-- .../gen/Resources/xlf/Strings.fr.xlf | 4 ++-- .../gen/Resources/xlf/Strings.it.xlf | 4 ++-- .../gen/Resources/xlf/Strings.ja.xlf | 4 ++-- .../gen/Resources/xlf/Strings.ko.xlf | 4 ++-- .../gen/Resources/xlf/Strings.pl.xlf | 4 ++-- .../gen/Resources/xlf/Strings.pt-BR.xlf | 4 ++-- .../gen/Resources/xlf/Strings.ru.xlf | 4 ++-- .../gen/Resources/xlf/Strings.tr.xlf | 4 ++-- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 4 ++-- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.cs.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.de.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.es.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.fr.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.it.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.ja.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.ko.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.pt-BR.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.ru.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.tr.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.zh-Hans.xlf | 2 +- .../gen/Common/Resources/xlf/Strings.zh-Hant.xlf | 2 +- .../System.Text.Json/gen/Resources/xlf/Strings.pl.xlf | 2 +- 29 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf index 29bfa35727e806..8c264bc592c9c0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + Jazyková verze projektu musí být alespoň C# 12 Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + Verze jazyka musí být alespoň C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf index fc071eba18289d..37100d25efae20 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + Die Sprachversion des Projekts muss mindestens "C# 12" sein. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + Die Sprachversion muss mindestens C# 12 sein. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf index 772e016401aaf5..00bf90592cc311 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + La versión del lenguaje del proyecto debe ser al menos "C# 12". Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + La versión del lenguaje debe ser al menos C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf index 29b944202c4577..847bc6155aaaee 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + La version de langage du projet doit être au moins 'C# 12'. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + La version du langage doit être au moins C# 12. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf index 2f6f0a32d918d8..9ee871268cff5a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + La versione del linguaggio del progetto deve essere almeno 'C# 12'. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + La versione del linguaggio deve essere almeno C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf index 56e8f33a179316..b7d5becee73ca2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + プロジェクトの言語バージョンは少なくとも 'C# 12' である必要があります。 Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + 言語バージョンは少なくとも C# 12 である必要があります diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf index fee49ec4680490..4c94c55903310e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + 프로젝트의 언어 버전은 'C# 12' 이상이어야 합니다. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + 언어 버전은 C# 12 이상이어야 합니다. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf index 8ea73703ba5058..808afa9723f55a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + Wersja językowa projektu musi mieć wartość co najmniej „C# 12”. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + Wymagana jest wersja językowa o wartości co najmniej C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf index 9486601e2438cf..9f723e7e6af48b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + A versão da linguagem do projeto deve ser no mínimo 'C# 12'. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + A versão do idioma deve ser pelo menos C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf index bbf81d0d807838..cc2f61c6e9d514 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + Версия языка проекта должна быть не ниже "C# 12". Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + Версия языка должна быть не ниже C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf index 1f2c2c6e9617e5..06aaaded5cf2c1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + Projenin dil sürümü en az 'C# 12' olmalıdır. Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + Dil sürümünün en az C# 12 olması gerekir diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf index ffc49d0c8b8b06..ef3affe4e22bcc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + 项目的语言版本必须至少为 "C# 12"。 Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + 语言版本必须至少为 C# 12 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf index 24a5268fc5f261..39dd659d8890dd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -29,12 +29,12 @@ The project's language version has to be at least 'C# 12'. - The project's language version has to be at least 'C# 12'. + 專案的語言版本必須至少為 'C# 12'。 Language version is required to be at least C# 12 - Language version is required to be at least C# 12 + 語言版本要求至少為 C#12 diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf index b7c27d6dc5a24b..a40b72d24ffcea 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Resources/xlf/Strings.pl.xlf @@ -69,7 +69,7 @@ The Logging source generator is not available in C# {0}. Please use language version {1} or greater. - The Logging source generator is not available in C# {0}. Please use language version {1} or greater. + Generator źródła rejestrowania nie jest dostępny w języku C# {0}. Użyj wersji językowej {1} lub nowszej. diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf index 5949f6a902609b..190ca17b561792 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Options/gen/Resources/xlf/Strings.pl.xlf @@ -124,7 +124,7 @@ The options validation source generator is not available in C# {0}. Please use language version {1} or greater. - The options validation source generator is not available in C# {0}. Please use language version {1} or greater. + Generator źródła sprawdzania poprawności opcji nie jest dostępny w języku C# {0}. Użyj wersji językowej {1} lub nowszej. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf index 829de99735954b..7f3261b6a59368 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf @@ -1311,4 +1311,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf index 1f959d763c7ba7..4661bf889dc59a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf @@ -1311,4 +1311,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf index fab077ea6bac23..7fdaa530d64fb8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf @@ -1311,4 +1311,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index 3f8638ef4ee7f8..35a71ca7310139 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - L’attribut '[Out]' est uniquement pris en charge sur les paramètres de tableau. Envisagez d’utiliser des mots clés 'out' ou 'ref' pour rendre le paramètre mutable. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf index d6ed0fd8fc3b35..6fae51e9aef95a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - L'attributo '[Out]' è supportato solo nei parametri di matrice. Provare a usare le parole chiave 'out' o 'ref' per rendere modificabile il parametro. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf index 0963a7a2aa5267..006bd7cf02b7f6 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf @@ -1312,4 +1312,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index 1cbdc68ed114d5..d40a4bf4760926 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -1311,4 +1311,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index 05433b6de67407..679e91c677c37f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Atrybut „[Out]” jest obsługiwany tylko w przypadku parametrów tablicy. Rozważ użycie słów kluczowych „out” lub „ref”, aby umożliwić modyfikowanie parametru. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index c608ba0d78a585..cd845a3992cc12 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -1311,4 +1311,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf index bee98c1d72e1f8..115cf30ac4c61c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - Атрибут "[Out]" поддерживается только для параметров массива. Рассмотрите возможность использования ключевых слов "out" или "ref", чтобы сделать параметр изменяемым. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf index ba0b8468207011..6bcbaf87980d36 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - '[Out]' özniteliği yalnızca dizi parametrelerinde desteklenir. Parametreyi değiştirilebilir yapmak için 'out' veya 'ref' anahtar sözcükleri kullanmayı düşünün. + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf index fd82f97082b4d8..240718627dd8e8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -1311,4 +1311,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf index a1998a248b2fdf..c6103229ee5c4f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - 只有陣列參數才支援 '[Out]' 屬性。請考慮使用 'out' 或 'ref' 關鍵字將參數設為可變。 + The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf index 3ac0444fdee2a2..d8e7a990013fac 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf @@ -114,7 +114,7 @@ The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. - The System.Text.Json source generator is not available in C# {0}. Please use language version {1} or greater. + Generator źródła System.Text.Json nie jest dostępny w języku C# {0}. Użyj wersji językowej {1} lub nowszej. From c09812fda3500d92fee034c44bd5b1a1f7fd5fd2 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Thu, 31 Aug 2023 01:20:42 -0700 Subject: [PATCH 116/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2256435 (#91360) --- .../gen/Common/Resources/xlf/Strings.fr.xlf | 16 ++++++++-------- .../gen/Common/Resources/xlf/Strings.ko.xlf | 16 ++++++++-------- .../gen/Common/Resources/xlf/Strings.pl.xlf | 16 ++++++++-------- .../gen/Common/Resources/xlf/Strings.pt-BR.xlf | 16 ++++++++-------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index 35a71ca7310139..50bffbbb83c75f 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -149,12 +149,12 @@ The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + L'utilisation de « GeneratedComInterfaceAttribute » ne suit pas les recommandations. {0} The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + L'utilisation de « GeneratedComInterfaceAttribute » ne suit pas les recommandations. @@ -459,7 +459,7 @@ The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. - The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + L'attribut '[In]' n'est pris en charge que sur les paramètres de tableau. Les paramètres par valeur sont considérés comme en lecture seule par défaut. @@ -484,7 +484,7 @@ The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. - The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + Les attributs '[In]' et '[Out]' ne sont pris en charge que sur les paramètres de tableau. Pensez à utiliser le mot-clé 'ref' pour rendre le paramètre mutable. @@ -724,12 +724,12 @@ The usage of 'LibraryImportAttribute' does not follow recommendations. {0} - The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + L'utilisation de « LibraryImport Attribute » ne suit pas les recommandations. {0} The usage of 'LibraryImportAttribute' does not follow recommendations. - The usage of 'LibraryImportAttribute' does not follow recommendations. + L'utilisation de « LibraryImport Attribute » ne suit pas les recommandations. @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + L'attribut '[Out]' n'est pris en charge que sur les paramètres de tableau. Pensez à utiliser les mots-clés « out » ou « ref » pour rendre le paramètre mutable. @@ -949,7 +949,7 @@ It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. - It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + Il est recommandé d'utiliser les attributs explicites '[In]' et '[Out]' sur les paramètres du tableau. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index d40a4bf4760926..d3d130445bab26 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -149,12 +149,12 @@ The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + 'GeneratedComInterfaceAttribute' 사용법이 권장 사항을 따르지 않습니다. {0} The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + 'GeneratedComInterfaceAttribute' 사용법이 권장 사항을 따르지 않습니다. @@ -459,7 +459,7 @@ The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. - The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + '[In]' 특성은 배열 매개 변수에서만 지원됩니다. 값별 매개 변수는 기본적으로 읽기 전용으로 간주됩니다. @@ -484,7 +484,7 @@ The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. - The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + '[In]' 및 '[Out]' 특성은 배열 매개 변수에서만 지원됩니다. 매개 변수를 변경 가능하게 만들려면 'ref' 키워드를 사용하는 것이 좋습니다. @@ -724,12 +724,12 @@ The usage of 'LibraryImportAttribute' does not follow recommendations. {0} - The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + 'LibraryImportAttribute' 사용법이 권장 사항을 따르지 않습니다. {0} The usage of 'LibraryImportAttribute' does not follow recommendations. - The usage of 'LibraryImportAttribute' does not follow recommendations. + 'LibraryImportAttribute' 사용법이 권장 사항을 따르지 않습니다. @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + '[Out]' 특성은 배열 매개 변수에서만 지원됩니다. 매개 변수를 변경할 수 있도록 'out' 또는 'ref' 키워드를 사용하는 것이 좋습니다. @@ -949,7 +949,7 @@ It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. - It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + 배열 매개 변수에는 명시적인 '[In]' 및 '[Out]' 특성을 사용하는 것이 좋습니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index 679e91c677c37f..c5dbc075109417 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -149,12 +149,12 @@ The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + Użycie atrybutu „GeneratedComInterfaceAttribute” nie jest zgodne z zaleceniami. {0} The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + Użycie atrybutu „GeneratedComInterfaceAttribute” nie jest zgodne z zaleceniami. @@ -459,7 +459,7 @@ The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. - The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + Atrybut „[In]” jest obsługiwany tylko w przypadku parametrów tablicy. Parametry według wartości są domyślnie uznawane za tylko do odczytu. @@ -484,7 +484,7 @@ The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. - The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + Atrybuty „[In]” i „[Out]” są obsługiwane tylko w przypadku parametrów tablicy. Rozważ użycie słowa kluczowego „ref”, aby umożliwić modyfikowanie parametru. @@ -724,12 +724,12 @@ The usage of 'LibraryImportAttribute' does not follow recommendations. {0} - The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + Użycie atrybutu „LibraryImportAttribute” nie jest zgodne z zaleceniami. {0} The usage of 'LibraryImportAttribute' does not follow recommendations. - The usage of 'LibraryImportAttribute' does not follow recommendations. + Użycie atrybutu „LibraryImportAttribute” nie jest zgodne z zaleceniami. @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + Atrybut „[Out]” jest obsługiwany tylko w przypadku parametrów tablicy. Rozważ użycie słów kluczowych „out” lub „ref”, aby umożliwić modyfikowanie parametru. @@ -949,7 +949,7 @@ It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. - It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + Zaleca się używanie jawnych atrybutów „[In]” i „[Out]” w parametrach tablicy. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index cd845a3992cc12..80bc83669b4547 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -149,12 +149,12 @@ The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. {0} + O uso de 'GeneratedComInterfaceAttribute' não segue as recomendações. {0} The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. - The usage of 'GeneratedComInterfaceAttribute' does not follow recommendations. + O uso de 'GeneratedComInterfaceAttribute' não segue as recomendações. @@ -459,7 +459,7 @@ The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. - The '[In]' attribute is only supported on array parameters. By-value parameters are considered read-only by default. + O '[In]' atributo só tem suporte nos parâmetros de matriz. Parâmetros por valor são considerados somente leitura por padrão. @@ -484,7 +484,7 @@ The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. - The '[In]' and '[Out]' attributes are only supported on array parameters. Consider using the 'ref' keyword to make the parameter mutable. + Os atributos '[In]' e '[Out]' só têm suporte nos parâmetros de matriz. Considere usar a palavra-chave 'ref' para tornar o parâmetro mutável. @@ -724,12 +724,12 @@ The usage of 'LibraryImportAttribute' does not follow recommendations. {0} - The usage of 'LibraryImportAttribute' does not follow recommendations. {0} + O uso de 'LibraryImportAttribute' não segue as recomendações. {0} The usage of 'LibraryImportAttribute' does not follow recommendations. - The usage of 'LibraryImportAttribute' does not follow recommendations. + O uso de 'LibraryImportAttribute' não segue as recomendações. @@ -934,7 +934,7 @@ The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. - The '[Out]' attribute is only supported on array parameters. Consider using 'out' or 'ref' keywords to make the parameter mutable. + O atributo "[Out]" só tem suporte nos parâmetros de matriz. Considere usar palavras-chave "out" ou "ref" para tornar o parâmetro mutável. @@ -949,7 +949,7 @@ It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. - It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters. + É recomendável usar atributos '[In]' e '[Out]' explícitos nos parâmetros de matriz. From 903c3a58d47b7de5dba3e9058ea7f0011f4285af Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 31 Aug 2023 08:42:42 -0700 Subject: [PATCH 117/345] [release/8.0] Update dependencies from dotnet/roslyn (#91239) * Update dependencies from https://github.com/dotnet/roslyn build 20230828.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-2.23428.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230828.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-2.23428.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230828.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-2.23428.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230828.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-2.23428.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230828.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23428.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230828.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23428.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230828.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23428.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-2.23429.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.9 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.12 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.12 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.13 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.13 * Update dependencies from https://github.com/dotnet/roslyn build 20230829.14 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23429.14 * Update dependencies from https://github.com/dotnet/roslyn build 20230830.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23430.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230830.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-2.23430.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230830.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23430.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230830.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23430.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230830.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23430.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230830.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-2.23426.1 -> To Version 4.8.0-3.23430.6 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e2026ba5907ba6..61b41ba5e21c1b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 34268d1bb9370c7b01c742303a895a99daf10d6a + 0a5289acaadde17d768b8f69dbc35aeec74cc4f8 - + https://github.com/dotnet/roslyn - 34268d1bb9370c7b01c742303a895a99daf10d6a + 0a5289acaadde17d768b8f69dbc35aeec74cc4f8 - + https://github.com/dotnet/roslyn - 34268d1bb9370c7b01c742303a895a99daf10d6a + 0a5289acaadde17d768b8f69dbc35aeec74cc4f8 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 8234d10cc507cc..4720bab4b03e0e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-2.23426.1 - 4.8.0-2.23426.1 - 4.8.0-2.23426.1 + 4.8.0-3.23430.6 + 4.8.0-3.23430.6 + 4.8.0-3.23430.6 diff --git a/eng/Versions.props b/eng/Versions.props index 4720bab4b03e0e..93153b418cab7c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23429.4 - 1.0.0-prerelease.23429.4 - 1.0.0-prerelease.23429.4 - 1.0.0-prerelease.23429.4 - 1.0.0-prerelease.23429.4 - 1.0.0-prerelease.23429.4 + 1.0.0-prerelease.23430.6 + 1.0.0-prerelease.23430.6 + 1.0.0-prerelease.23430.6 + 1.0.0-prerelease.23430.6 + 1.0.0-prerelease.23430.6 + 1.0.0-prerelease.23430.6 16.11.27-beta1.23180.1 2.0.0-beta4.23307.1 From 35f043f414dbd234978f0eb694b47dfb42dd2031 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Thu, 31 Aug 2023 15:25:40 -0700 Subject: [PATCH 120/345] Update binder gen emitted-interceptor nullability to match framework impl (#91180) (#91359) --- .../ConfigurationBindingGenerator.Emitter.cs | 12 +- .../Helpers/Emitter/ConfigurationBinder.cs | 15 +- .../gen/Helpers/Emitter/CoreBindingHelpers.cs | 45 ++--- .../gen/Helpers/Emitter/Helpers.cs | 12 +- .../OptionsBuilderConfigurationExtensions.cs | 19 +- ...onfigurationServiceCollectionExtensions.cs | 16 +- .../gen/Helpers/MethodsToGen.cs | 14 +- .../gen/Helpers/Parser/ConfigurationBinder.cs | 8 +- .../OptionsBuilderConfigurationExtensions.cs | 8 +- ...onfigurationServiceCollectionExtensions.cs | 7 +- .../gen/Model/ObjectSpec.cs | 4 +- .../src/ConfigurationBinder.cs | 182 +++++++++--------- .../tests/Common/ConfigurationBinderTests.cs | 83 +++++++- .../Baselines/Collections.generated.txt | 56 +++--- .../ConfigurationBinder/Bind.generated.txt | 56 +++--- .../Bind_Instance.generated.txt | 40 ++-- .../Bind_Instance_BinderOptions.generated.txt | 40 ++-- .../Bind_Key_Instance.generated.txt | 40 ++-- .../ConfigurationBinder/Get.generated.txt | 50 ++--- .../ConfigurationBinder/Get_T.generated.txt | 40 ++-- .../Get_T_BinderOptions.generated.txt | 40 ++-- .../Get_TypeOf.generated.txt | 10 +- .../Get_TypeOf_BinderOptions.generated.txt | 10 +- .../BindConfiguration.generated.txt | 44 ++--- .../OptionsBuilder/Bind_T.generated.txt | 45 ++--- .../Bind_T_BinderOptions.generated.txt | 41 ++-- .../Baselines/Primitives.generated.txt | 66 +++---- .../Configure_T.generated.txt | 61 +++--- .../Configure_T_BinderOptions.generated.txt | 61 +++--- .../Configure_T_name.generated.txt | 61 +++--- ...nfigure_T_name_BinderOptions.generated.txt | 57 +++--- .../SourceGenerationTests/GeneratorTests.cs | 6 +- .../Common/ConfigurationExtensionsTests.cs | 55 ++++++ ...s.ConfigurationExtensions.UnitTests.csproj | 3 +- 34 files changed, 699 insertions(+), 608 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs index 756e10bc26b8d5..cb67c7ee1f5fb9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs @@ -96,19 +96,19 @@ private void EmitBindCoreCall( EmitBindCoreCall(memberAccessExpr, initKind); } - void EmitBindCoreCall(string objExpression, InitializationKind initKind) + void EmitBindCoreCall(string instanceExpr, InitializationKind initKind) { - string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});"; - EmitObjectInit(objExpression, initKind); + string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {instanceExpr}, {Identifier.binderOptions});"; + EmitObjectInit(instanceExpr, initKind); _writer.WriteLine(bindCoreCall); - writeOnSuccess?.Invoke(objExpression); + writeOnSuccess?.Invoke(instanceExpr); } - void EmitObjectInit(string objExpression, InitializationKind initKind) + void EmitObjectInit(string instanceExpr, InitializationKind initKind) { if (initKind is not InitializationKind.None) { - this.EmitObjectInit(type, objExpression, initKind, configArgExpr); + this.EmitObjectInit(type, instanceExpr, initKind, configArgExpr); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs index 64064887c7c70b..c7ead12d65589d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -101,13 +100,13 @@ private void EmitBindMethods_ConfigurationBinder() return; } - string objParamExpr = $"object? {Identifier.obj}"; + string instanceParamExpr = $"object? {Identifier.instance}"; if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance)) { EmitMethods( MethodsToGen_ConfigurationBinder.Bind_instance, - additionalParams: objParamExpr, + additionalParams: instanceParamExpr, configExpression: Identifier.configuration, configureOptions: false); } @@ -116,7 +115,7 @@ private void EmitBindMethods_ConfigurationBinder() { EmitMethods( MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, - additionalParams: $"{objParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}", + additionalParams: $"{instanceParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}", configExpression: Identifier.configuration, configureOptions: true); } @@ -125,7 +124,7 @@ private void EmitBindMethods_ConfigurationBinder() { EmitMethods( MethodsToGen_ConfigurationBinder.Bind_key_instance, - additionalParams: $"string {Identifier.key}, {objParamExpr}", + additionalParams: $"string {Identifier.key}, {instanceParamExpr}", configExpression: $"{Expression.configurationGetSection}({Identifier.key})", configureOptions: false); } @@ -141,17 +140,17 @@ void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParam EmitInterceptsLocationAnnotations(interceptorInfoList); EmitStartBlock($"public static void {Identifier.Bind}_{type.DisplayString.ToIdentifierSubstring()}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})"); - if (!EmitInitException(type) && type.NeedsMemberBinding) + if (type.NeedsMemberBinding) { string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null"; EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); if (!type.IsValueType) { - EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + EmitCheckForNullArgument_WithBlankLine(Identifier.instance, voidReturn: true); } _writer.WriteLine($$""" - var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.obj}}; + var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.instance}}; {{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, {{binderOptionsArg}}); """); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs index f30408fad596dd..bb2bd7ac61d15a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs @@ -101,8 +101,8 @@ private void EmitGetCoreMethod() } else if (!EmitInitException(effectiveType)) { - EmitBindCoreCall(effectiveType, Identifier.obj, Identifier.configuration, InitializationKind.Declaration); - _writer.WriteLine($"return {Identifier.obj};"); + EmitBindCoreCall(effectiveType, Identifier.instance, Identifier.configuration, InitializationKind.Declaration); + _writer.WriteLine($"return {Identifier.instance};"); } EmitEndBlock(); @@ -168,9 +168,8 @@ private void EmitBindCoreMainMethod() } EmitBlankLineIfRequired(); - EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); - EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); - EmitCheckForNullArgument_WithBlankLine(Identifier.obj); + EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.instance}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); + EmitCheckForNullArgument_WithBlankLine(Identifier.instance, voidReturn: true); EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true); _writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});"); _writer.WriteLine(); @@ -184,7 +183,7 @@ private void EmitBindCoreMainMethod() EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); if (!EmitInitException(effectiveType)) { - _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.obj};"); + _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.instance};"); EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None); _writer.WriteLine($"return;"); } @@ -213,9 +212,7 @@ private void EmitBindCoreMethods() private void EmitBindCoreMethod(TypeSpec type) { - Debug.Assert(type.CanInitialize); - - string objParameterExpression = $"ref {type.DisplayString} {Identifier.obj}"; + string objParameterExpression = $"ref {type.DisplayString} {Identifier.instance}"; EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})"); TypeSpec effectiveType = type.EffectiveType; @@ -618,15 +615,15 @@ private void EmitPopulationImplForArray(EnumerableSpec type) // Resize array and add binded elements. _writer.WriteLine($$""" - {{Identifier.Int32}} {{Identifier.originalCount}} = {{Identifier.obj}}.{{Identifier.Length}}; - {{Identifier.Array}}.{{Identifier.Resize}}(ref {{Identifier.obj}}, {{Identifier.originalCount}} + {{tempIdentifier}}.{{Identifier.Count}}); - {{tempIdentifier}}.{{Identifier.CopyTo}}({{Identifier.obj}}, {{Identifier.originalCount}}); + {{Identifier.Int32}} {{Identifier.originalCount}} = {{Identifier.instance}}.{{Identifier.Length}}; + {{Identifier.Array}}.{{Identifier.Resize}}(ref {{Identifier.instance}}, {{Identifier.originalCount}} + {{tempIdentifier}}.{{Identifier.Count}}); + {{tempIdentifier}}.{{Identifier.CopyTo}}({{Identifier.instance}}, {{Identifier.originalCount}}); """); } private void EmitPopulationImplForEnumerableWithAdd(EnumerableSpec type) { - EmitCollectionCastIfRequired(type, out string objIdentifier); + EmitCollectionCastIfRequired(type, out string instanceIdentifier); Emit_Foreach_Section_In_ConfigChildren_StartBlock(); @@ -638,14 +635,14 @@ private void EmitPopulationImplForEnumerableWithAdd(EnumerableSpec type) stringParsableType, Expression.sectionValue, Expression.sectionPath, - (parsedValueExpr) => _writer.WriteLine($"{objIdentifier}.{Identifier.Add}({parsedValueExpr});"), + (parsedValueExpr) => _writer.WriteLine($"{instanceIdentifier}.{Identifier.Add}({parsedValueExpr});"), checkForNullSectionValue: true, useIncrementalStringValueIdentifier: false); } else { EmitBindCoreCall(elementType, Identifier.value, Identifier.section, InitializationKind.Declaration); - _writer.WriteLine($"{objIdentifier}.{Identifier.Add}({Identifier.value});"); + _writer.WriteLine($"{instanceIdentifier}.{Identifier.Add}({Identifier.value});"); } EmitEndBlock(); @@ -653,7 +650,7 @@ private void EmitPopulationImplForEnumerableWithAdd(EnumerableSpec type) private void EmitBindCoreImplForDictionary(DictionarySpec type) { - EmitCollectionCastIfRequired(type, out string objIdentifier); + EmitCollectionCastIfRequired(type, out string instanceIdentifier); Emit_Foreach_Section_In_ConfigChildren_StartBlock(); @@ -677,7 +674,7 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) stringParsableElementType, Expression.sectionValue, Expression.sectionPath, - writeOnSuccess: parsedValueExpr => _writer.WriteLine($"{objIdentifier}[{parsedKeyExpr}] = {parsedValueExpr};"), + writeOnSuccess: parsedValueExpr => _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {parsedValueExpr};"), checkForNullSectionValue: true, useIncrementalStringValueIdentifier: false); } @@ -696,7 +693,7 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) string expressionForElementIsNotNull = $"{Identifier.element} is not null"; string elementTypeDisplayString = elementType.DisplayString + (elementType.IsValueType ? string.Empty : "?"); - string expressionForElementExists = $"{objIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})"; + string expressionForElementExists = $"{instanceIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})"; string conditionToUseExistingElement = expressionForElementExists; // If key already exists, bind to existing element instance if not null (for ref types). @@ -727,7 +724,7 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) } EmitBindCoreCall(elementType, Identifier.element, Identifier.section, InitializationKind.None); - _writer.WriteLine($"{objIdentifier}[{parsedKeyExpr}] = {Identifier.element};"); + _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {Identifier.element};"); } } @@ -747,7 +744,7 @@ private void EmitBindCoreImplForObject(ObjectSpec type) bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor }; if (property.ShouldBind() && !noSetter_And_IsReadonly) { - string containingTypeRef = property.IsStatic ? type.DisplayString : Identifier.obj; + string containingTypeRef = property.IsStatic ? type.DisplayString : Identifier.instance; EmitBindImplForMember( property, memberAccessExpr: $"{containingTypeRef}.{property.Name}", @@ -883,14 +880,14 @@ private void EmitBindCoreCallForMember( writeOnSuccess); } - private void EmitCollectionCastIfRequired(CollectionSpec type, out string objIdentifier) + private void EmitCollectionCastIfRequired(CollectionSpec type, out string instanceIdentifier) { - objIdentifier = Identifier.obj; + instanceIdentifier = Identifier.instance; if (type.PopulationStrategy is CollectionPopulationStrategy.Cast_Then_Add) { - objIdentifier = Identifier.temp; + instanceIdentifier = Identifier.temp; _writer.WriteLine($$""" - if ({{Identifier.obj}} is not {{type.PopulationCastType!.DisplayString}} {{objIdentifier}}) + if ({{Identifier.instance}} is not {{type.PopulationCastType!.DisplayString}} {{instanceIdentifier}}) { return; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index bad56b7ce3275a..909272c7678447 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -45,6 +45,8 @@ private static class TypeDisplayString private static class Identifier { public const string binderOptions = nameof(binderOptions); + public const string config = nameof(config); + public const string configureBinder = nameof(configureBinder); public const string configureOptions = nameof(configureOptions); public const string configuration = nameof(configuration); public const string configSectionPath = nameof(configSectionPath); @@ -55,7 +57,7 @@ private static class Identifier public const string getPath = nameof(getPath); public const string key = nameof(key); public const string name = nameof(name); - public const string obj = nameof(obj); + public const string instance = nameof(instance); public const string optionsBuilder = nameof(optionsBuilder); public const string originalCount = nameof(originalCount); public const string section = nameof(section); @@ -211,12 +213,16 @@ private void EmitBlankLineIfRequired() _emitBlankLineBeforeNextStatement = true; } - private void EmitCheckForNullArgument_WithBlankLine(string paramName) + private void EmitCheckForNullArgument_WithBlankLine(string paramName, bool voidReturn = false) { + string returnExpr = voidReturn + ? "return" + : $"throw new ArgumentNullException(nameof({paramName}))"; + _writer.WriteLine($$""" if ({{paramName}} is null) { - throw new ArgumentNullException(nameof({{paramName}})); + {{returnExpr}}; } """); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs index d49198196fd491..7fd5d695eaf45a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs @@ -30,25 +30,25 @@ private void EmitBindMethods_Extensions_OptionsBuilder() } const string documentation = @"/// Registers a configuration instance which will bind against."; - const string paramList = $"{Identifier.IConfiguration} {Identifier.configuration}"; + const string paramList = $"{Identifier.IConfiguration} {Identifier.config}"; if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T)) { EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.Bind_T, "Bind", paramList, documentation); - _writer.WriteLine($"return Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); + _writer.WriteLine($"return Bind({Identifier.optionsBuilder}, {Identifier.config}, {Identifier.configureBinder}: null);"); EmitEndBlock(); } EmitMethodStartBlock( MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions, "Bind", - paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}", + paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureBinder}", documentation); EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder); _writer.WriteLine($$""" - {{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}}); + {{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.config}}, {{Identifier.configureBinder}}); return {{Identifier.optionsBuilder}}; """); @@ -63,19 +63,18 @@ private void EmitBindConfigurationMethod() } const string documentation = $@"/// Registers the dependency injection container to bind against the obtained from the DI service provider."; - string paramList = $"string {Identifier.configSectionPath}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions} = null"; + string paramList = $"string {Identifier.configSectionPath}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureBinder} = null"; EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration, "BindConfiguration", paramList, documentation); EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder); EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath); - EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>"); - EmitCheckForNullArgument_WithBlankLine(Identifier.obj); - EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); + EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.instance}, {Identifier.config}) =>"); + EmitCheckForNullArgument_WithBlankLine(Identifier.config); _writer.WriteLine($$""" - {{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}}); - {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}); + {{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.config}} : {{Identifier.config}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}}); + {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.instance}}, typeof({{Identifier.TOptions}}), {{Identifier.configureBinder}}); """); EmitEndBlock(endBraceTrailingSource: ");"); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs index 41eeb8b657342d..7577e0c49de4d0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs @@ -24,12 +24,12 @@ private void EmitBindingExtensions_IServiceCollection() private void EmitConfigureMethods() { const string defaultNameExpr = "string.Empty"; - string configParam = $"{Identifier.IConfiguration} {Identifier.configuration}"; + string configParam = $"{Identifier.IConfiguration} {Identifier.config}"; if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T)) { EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T, configParam); - _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); + _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.config}, {Identifier.configureOptions}: null);"); EmitEndBlock(); } @@ -38,7 +38,7 @@ private void EmitConfigureMethods() EmitStartMethod( MethodsToGen_Extensions_ServiceCollection.Configure_T_name, paramList: $"string? {Identifier.name}, " + configParam); - _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);"); + _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.config}, {Identifier.configureOptions}: null);"); EmitEndBlock(); } @@ -47,22 +47,20 @@ private void EmitConfigureMethods() EmitStartMethod( MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions, paramList: configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}"); - _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});"); + _writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.config}, {Identifier.configureOptions});"); EmitEndBlock(); } // Core Configure method that the other overloads call. // Like the others, it is public API that could be called directly by users. // So, it is always generated whenever a Configure overload is called. - string optionsNamespaceName = "Microsoft.Extensions.Options"; - EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, paramList: $"string? {Identifier.name}, " + configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}"); EmitCheckForNullArgument_WithBlankLine(Identifier.services); - EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); + EmitCheckForNullArgument_WithBlankLine(Identifier.config); _writer.WriteLine($$""" OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}}); - {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}})); - return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}))); + {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.config}})); + return {{Identifier.services}}.{{Identifier.AddSingleton}}>(new ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.instance}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.config}}, {{Identifier.instance}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}}))); """); EmitEndBlock(); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs index 2c582b20e8ebd6..6165a3e6d46dcb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs @@ -27,17 +27,17 @@ internal enum MethodsToGen_ConfigurationBinder None = 0x0, /// - /// Bind(IConfiguration, object). + /// Bind(IConfiguration, object?). /// Bind_instance = 0x1, /// - /// Bind(IConfiguration, object, Action). + /// Bind(IConfiguration, object?, Action?). /// Bind_instance_BinderOptions = 0x2, /// - /// Bind(IConfiguration, string, object). + /// Bind(IConfiguration, string, object?). /// Bind_key_instance = 0x4, @@ -47,17 +47,17 @@ internal enum MethodsToGen_ConfigurationBinder Get_T = 0x8, /// - /// Get(IConfiguration, Action). + /// Get(IConfiguration, Action?). /// Get_T_BinderOptions = 0x10, /// - /// Get(IConfiguration, Type). + /// Get(IConfiguration, Type). /// Get_TypeOf = 0x20, /// - /// Get(IConfiguration, Type, Action). + /// Get(IConfiguration, Type, Action?). /// Get_TypeOf_BinderOptions = 0x40, @@ -67,7 +67,7 @@ internal enum MethodsToGen_ConfigurationBinder GetValue_TypeOf_key = 0x80, /// - /// GetValue(IConfiguration, Type, object). + /// GetValue(IConfiguration, Type, object?). /// GetValue_TypeOf_key_defaultValue = 0x100, diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs index e24ce11fe4374c..bce30222493841 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs @@ -72,7 +72,7 @@ private void RegisterBindInvocation(BinderInvocation invocation) return; } - int objectIndex = overload switch + int instanceIndex = overload switch { MethodsToGen_ConfigurationBinder.Bind_instance => 1, MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => 1, @@ -80,13 +80,13 @@ private void RegisterBindInvocation(BinderInvocation invocation) _ => throw new InvalidOperationException() }; - IArgumentOperation objectArg = operation.Arguments[objectIndex]; - if (objectArg.Parameter.Type.SpecialType != SpecialType.System_Object) + IArgumentOperation instanceArg = operation.Arguments[instanceIndex]; + if (instanceArg.Parameter.Type.SpecialType != SpecialType.System_Object) { return; } - ITypeSymbol? type = ResolveType(objectArg.Value)?.WithNullableAnnotation(NullableAnnotation.None); + ITypeSymbol? type = ResolveType(instanceArg.Value)?.WithNullableAnnotation(NullableAnnotation.None); if (!IsValidRootConfigType(type)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs index a62e63c0d90d5e..f65c67a7878b1a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs @@ -25,9 +25,11 @@ private void RegisterMethodInvocation_OptionsBuilderExt(BinderInvocation invocat return; } - TypeSpec typeSpec = GetTargetTypeForRootInvocation( - type: targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None), - invocation.Location); + + ITypeSymbol? typeSymbol = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None); + // This would violate generic type constraint; any such invocation could not have been included in the initial parser. + Debug.Assert(typeSymbol?.IsValueType is not true); + TypeSpec typeSpec = GetTargetTypeForRootInvocation(typeSymbol, invocation.Location); if (typeSpec is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs index c356b29a69efff..b811a8e6ae0eca 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -69,9 +69,10 @@ @params[1].Type.SpecialType is SpecialType.System_String && return; } - TypeSpec typeSpec = GetTargetTypeForRootInvocation( - type: targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None), - invocation.Location); + ITypeSymbol? typeSymbol = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None); + // This would violate generic type constraint; any such invocation could not have been included in the initial parser. + Debug.Assert(typeSymbol?.IsValueType is not true); + TypeSpec typeSpec = GetTargetTypeForRootInvocation(typeSymbol, invocation.Location); if (typeSpec is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs index 8cc0ba68b49381..09008dde159ad8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs @@ -22,8 +22,6 @@ public ObjectSpec(INamedTypeSymbol type) : base(type) { } public List ConstructorParameters { get; } = new(); - public override bool NeedsMemberBinding => CanInitialize && - Properties.Values.Count > 0 && - Properties.Values.Any(p => p.ShouldBind()); + public override bool NeedsMemberBinding => Properties.Values.Any(p => p.ShouldBind()); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index 8651e4922e0d72..74365d8084aa3d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -91,6 +91,7 @@ public static class ConfigurationBinder Action? configureOptions) { ThrowHelper.ThrowIfNull(configuration); + ThrowHelper.ThrowIfNull(type); var options = new BinderOptions(); configureOptions?.Invoke(options); @@ -108,7 +109,10 @@ public static class ConfigurationBinder [RequiresDynamicCode(DynamicCodeWarningMessage)] [RequiresUnreferencedCode(InstanceGetTypeTrimmingWarningMessage)] public static void Bind(this IConfiguration configuration, string key, object? instance) - => configuration.GetSection(key).Bind(instance); + { + ThrowHelper.ThrowIfNull(configuration); + configuration.GetSection(key).Bind(instance); + } /// /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. @@ -200,6 +204,9 @@ public static void Bind(this IConfiguration configuration, object? instance, Act Type type, string key, object? defaultValue) { + ThrowHelper.ThrowIfNull(configuration); + ThrowHelper.ThrowIfNull(type); + IConfigurationSection section = configuration.GetSection(key); string? value = section.Value; if (value != null) @@ -305,125 +312,122 @@ private static void BindInstance( return; } - if (config != null) + if (config.GetChildren().Any()) { - if (config.GetChildren().Any()) + // for arrays and read-only list-like interfaces, we concatenate on to what is already there, if we can + if (type.IsArray || IsImmutableArrayCompatibleInterface(type)) { - // for arrays and read-only list-like interfaces, we concatenate on to what is already there, if we can - if (type.IsArray || IsImmutableArrayCompatibleInterface(type)) + if (!bindingPoint.IsReadOnly) { - if (!bindingPoint.IsReadOnly) - { - bindingPoint.SetValue(BindArray(type, (IEnumerable?)bindingPoint.Value, config, options)); - } - - // for getter-only collection properties that we can't add to, nothing more we can do - return; + bindingPoint.SetValue(BindArray(type, (IEnumerable?)bindingPoint.Value, config, options)); } - // ----------------------------------------------------------------------------------------------------------------------------- - // | bindingPoint | bindingPoint | - // Interface | Value | IsReadOnly | Behavior - // ----------------------------------------------------------------------------------------------------------------------------- - // ISet | not null | true/false | Use the Value instance to populate the configuration - // ISet | null | false | Create HashSet instance to populate the configuration - // ISet | null | true | nothing - // IReadOnlySet | null/not null | false | Create HashSet instance, copy over existing values, and populate the configuration - // IReadOnlySet | null/not null | true | nothing - // ----------------------------------------------------------------------------------------------------------------------------- - if (TypeIsASetInterface(type)) - { - if (!bindingPoint.IsReadOnly || bindingPoint.Value is not null) - { - object? newValue = BindSet(type, (IEnumerable?)bindingPoint.Value, config, options); - if (!bindingPoint.IsReadOnly && newValue != null) - { - bindingPoint.SetValue(newValue); - } - } - - return; - } + // for getter-only collection properties that we can't add to, nothing more we can do + return; + } - // ----------------------------------------------------------------------------------------------------------------------------- - // | bindingPoint | bindingPoint | - // Interface | Value | IsReadOnly | Behavior - // ----------------------------------------------------------------------------------------------------------------------------- - // IDictionary | not null | true/false | Use the Value instance to populate the configuration - // IDictionary | null | false | Create Dictionary instance to populate the configuration - // IDictionary | null | true | nothing - // IReadOnlyDictionary | null/not null | false | Create Dictionary instance, copy over existing values, and populate the configuration - // IReadOnlyDictionary | null/not null | true | nothing - // ----------------------------------------------------------------------------------------------------------------------------- - if (TypeIsADictionaryInterface(type)) + // ----------------------------------------------------------------------------------------------------------------------------- + // | bindingPoint | bindingPoint | + // Interface | Value | IsReadOnly | Behavior + // ----------------------------------------------------------------------------------------------------------------------------- + // ISet | not null | true/false | Use the Value instance to populate the configuration + // ISet | null | false | Create HashSet instance to populate the configuration + // ISet | null | true | nothing + // IReadOnlySet | null/not null | false | Create HashSet instance, copy over existing values, and populate the configuration + // IReadOnlySet | null/not null | true | nothing + // ----------------------------------------------------------------------------------------------------------------------------- + if (TypeIsASetInterface(type)) + { + if (!bindingPoint.IsReadOnly || bindingPoint.Value is not null) { - if (!bindingPoint.IsReadOnly || bindingPoint.Value is not null) + object? newValue = BindSet(type, (IEnumerable?)bindingPoint.Value, config, options); + if (!bindingPoint.IsReadOnly && newValue != null) { - object? newValue = BindDictionaryInterface(bindingPoint.Value, type, config, options); - if (!bindingPoint.IsReadOnly && newValue != null) - { - bindingPoint.SetValue(newValue); - } + bindingPoint.SetValue(newValue); } - - return; } - // If we don't have an instance, try to create one - if (bindingPoint.Value is null) + return; + } + + // ----------------------------------------------------------------------------------------------------------------------------- + // | bindingPoint | bindingPoint | + // Interface | Value | IsReadOnly | Behavior + // ----------------------------------------------------------------------------------------------------------------------------- + // IDictionary | not null | true/false | Use the Value instance to populate the configuration + // IDictionary | null | false | Create Dictionary instance to populate the configuration + // IDictionary | null | true | nothing + // IReadOnlyDictionary | null/not null | false | Create Dictionary instance, copy over existing values, and populate the configuration + // IReadOnlyDictionary | null/not null | true | nothing + // ----------------------------------------------------------------------------------------------------------------------------- + if (TypeIsADictionaryInterface(type)) + { + if (!bindingPoint.IsReadOnly || bindingPoint.Value is not null) { - // if the binding point doesn't let us set a new instance, there's nothing more we can do - if (bindingPoint.IsReadOnly) + object? newValue = BindDictionaryInterface(bindingPoint.Value, type, config, options); + if (!bindingPoint.IsReadOnly && newValue != null) { - return; + bindingPoint.SetValue(newValue); } + } - Type? interfaceGenericType = type.IsInterface && type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : null; + return; + } - if (interfaceGenericType is not null && - (interfaceGenericType == typeof(ICollection<>) || interfaceGenericType == typeof(IList<>))) - { - // For ICollection and IList we bind them to mutable List type. - Type genericType = typeof(List<>).MakeGenericType(type.GenericTypeArguments); - bindingPoint.SetValue(Activator.CreateInstance(genericType)); - } - else - { - bindingPoint.SetValue(CreateInstance(type, config, options)); - } + // If we don't have an instance, try to create one + if (bindingPoint.Value is null) + { + // if the binding point doesn't let us set a new instance, there's nothing more we can do + if (bindingPoint.IsReadOnly) + { + return; } - Debug.Assert(bindingPoint.Value is not null); - - // At this point we know that we have a non-null bindingPoint.Value, we just have to populate the items - // using the IDictionary<> or ICollection<> interfaces, or properties using reflection. - Type? dictionaryInterface = FindOpenGenericInterface(typeof(IDictionary<,>), type); + Type? interfaceGenericType = type.IsInterface && type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : null; - if (dictionaryInterface != null) + if (interfaceGenericType is not null && + (interfaceGenericType == typeof(ICollection<>) || interfaceGenericType == typeof(IList<>))) { - BindDictionary(bindingPoint.Value, dictionaryInterface, config, options); + // For ICollection and IList we bind them to mutable List type. + Type genericType = typeof(List<>).MakeGenericType(type.GenericTypeArguments); + bindingPoint.SetValue(Activator.CreateInstance(genericType)); } else { - Type? collectionInterface = FindOpenGenericInterface(typeof(ICollection<>), type); - if (collectionInterface != null) - { - BindCollection(bindingPoint.Value, collectionInterface, config, options); - } - else - { - BindProperties(bindingPoint.Value, config, options); - } + bindingPoint.SetValue(CreateInstance(type, config, options)); } } + + Debug.Assert(bindingPoint.Value is not null); + + // At this point we know that we have a non-null bindingPoint.Value, we just have to populate the items + // using the IDictionary<> or ICollection<> interfaces, or properties using reflection. + Type? dictionaryInterface = FindOpenGenericInterface(typeof(IDictionary<,>), type); + + if (dictionaryInterface != null) + { + BindDictionary(bindingPoint.Value, dictionaryInterface, config, options); + } else { - if (isParentCollection) + Type? collectionInterface = FindOpenGenericInterface(typeof(ICollection<>), type); + if (collectionInterface != null) + { + BindCollection(bindingPoint.Value, collectionInterface, config, options); + } + else { - bindingPoint.TrySetValue(CreateInstance(type, config, options)); + BindProperties(bindingPoint.Value, config, options); } } } + else + { + if (isParentCollection) + { + bindingPoint.TrySetValue(CreateInstance(type, config, options)); + } + } } [RequiresDynamicCode(DynamicCodeWarningMessage)] diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index eea01092667e8d..a7e0474028172b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -2098,14 +2098,9 @@ public void CanBindToObjectMembers() TestBind(options => config.GetSection("Local").Bind(RemoteAuthenticationOptions.s_NonGenericField), obj => RemoteAuthenticationOptions.s_NonGenericField); // No null refs. -#if BUILDING_SOURCE_GENERATOR_TESTS - - Assert.Throws(() => config.GetSection("Local").Bind(new RemoteAuthenticationOptions().NullGenericProp)); - Assert.Throws(() => config.GetSection("Local").Bind(RemoteAuthenticationOptions.s_NullNonGenericField)); -#else config.GetSection("Local").Bind(new RemoteAuthenticationOptions().NullGenericProp); config.GetSection("Local").Bind(RemoteAuthenticationOptions.s_NullNonGenericField); -#endif + static void TestBind(Action> configure, Func, OidcProviderOptions> getBindedProp) { var obj = new RemoteAuthenticationOptions(); @@ -2121,5 +2116,81 @@ public void BinderSupportsObjCreationInput() // No diagnostic warning SYSLIB1104. configuration.Bind(new GraphWithUnsupportedMember()); } + + [Fact] + public void TestNullHandling_Get() + { + // Null configuration. + IConfiguration? configuration = null; + + Assert.Throws(() => configuration.Get()); + Assert.Throws(() => configuration.Get(_ => { })); + Assert.Throws(() => configuration.Get()); + Assert.Throws(() => configuration.Get(_ => { })); + + // Null Type. + configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); +#pragma warning disable SYSLIB1104 // The target type for a binder call could not be determined + Assert.Throws(() => configuration.Get(type: null)); + Assert.Throws(() => configuration.Get(type: null, _ => { })); +#pragma warning restore SYSLIB1104 // The target type for a binder call could not be determined + } + + [Fact] + public void TestNullHandling_GetValue() + { + string key = "Longitude"; + + // Null configuration. + Test(configuration: null, key); + + // Null type. + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); +#pragma warning disable SYSLIB1104 // The target type for a binder call could not be determined + Assert.Throws(() => configuration.GetValue(type: null, key)); + Assert.Throws(() => configuration.GetValue(type: null, key, defaultValue: null)); +#pragma warning restore SYSLIB1104 // The target type for a binder call could not be determined + + // Null key. + Test(configuration: configuration, key: null); + + void Test(IConfiguration? configuration, string? key) + { + Assert.Throws(() => configuration.GetValue(key)); + Assert.Throws(() => configuration.GetValue(key, defaultValue: null)); + Assert.Throws(() => configuration.GetValue(key)); + Assert.Throws(() => configuration.GetValue(key, defaultValue: default)); + TestUntypedOverloads(configuration: null, key); + } + + void TestUntypedOverloads(IConfiguration? configuration, string? key) + { + Assert.Throws(() => configuration.GetValue(typeof(GeolocationClass), key)); + Assert.Throws(() => configuration.GetValue(typeof(GeolocationClass), key, defaultValue: null)); + Assert.Throws(() => configuration.GetValue(typeof(GeolocationClass), key, new GeolocationClass())); + Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key)); + Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key, defaultValue: null)); + Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key, default(Geolocation))); + } + } + + [Fact] + public void TestNullHandling_Bind() + { + // Null configuration. + IConfiguration? configuration = null; + GeolocationClass? location = new(); + Assert.Throws(() => configuration.Bind(location)); + Assert.Throws(() => configuration.Bind(location, _ => { })); + Assert.Throws(() => configuration.Bind("", location)); + + // Null object. + configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Longitude"":1,""Latitude"":2}"); + location = null; + // Expect no exceptions. + configuration.Bind(location); + configuration.Bind(location, _ => { }); + configuration.Bind("", location); + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index 528847cfeb3a37..5f186e42e4da7d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -55,61 +55,61 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClassWithCustomCollections)) { - var obj = new Program.MyClassWithCustomCollections(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClassWithCustomCollections(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = ParseInt(value, () => section.Path); + instance[section.Key] = ParseInt(value, () => section.Path); } } } - public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.CustomList instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(value); + instance.Add(value); } } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref ICollection obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref ICollection instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref IReadOnlyList obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IReadOnlyList instance, BinderOptions? binderOptions) { - if (obj is not ICollection temp) + if (instance is not ICollection temp) { return; } @@ -123,31 +123,31 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = ParseInt(value, () => section.Path); + instance[section.Key] = ParseInt(value, () => section.Path); } } } - public static void BindCore(IConfiguration configuration, ref IDictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IDictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = ParseInt(value, () => section.Path); + instance[section.Key] = ParseInt(value, () => section.Path); } } } - public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary instance, BinderOptions? binderOptions) { - if (obj is not IDictionary temp) + if (instance is not IDictionary temp) { return; } @@ -161,40 +161,40 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1) { - Program.CustomDictionary? temp3 = obj.CustomDictionary; + Program.CustomDictionary? temp3 = instance.CustomDictionary; temp3 ??= new Program.CustomDictionary(); BindCore(section1, ref temp3, binderOptions); - obj.CustomDictionary = temp3; + instance.CustomDictionary = temp3; } if (AsConfigWithChildren(configuration.GetSection("CustomList")) is IConfigurationSection section4) { - Program.CustomList? temp6 = obj.CustomList; + Program.CustomList? temp6 = instance.CustomList; temp6 ??= new Program.CustomList(); BindCore(section4, ref temp6, binderOptions); - obj.CustomList = temp6; + instance.CustomList = temp6; } if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section7) { - IReadOnlyList? temp9 = obj.IReadOnlyList; + IReadOnlyList? temp9 = instance.IReadOnlyList; temp9 = temp9 is null ? new List() : new List(temp9); BindCore(section7, ref temp9, binderOptions); - obj.IReadOnlyList = temp9; + instance.IReadOnlyList = temp9; } if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section10) { - IReadOnlyDictionary? temp12 = obj.IReadOnlyDictionary; + IReadOnlyDictionary? temp12 = instance.IReadOnlyDictionary; temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); BindCore(section10, ref temp12, binderOptions); - obj.IReadOnlyDictionary = temp12; + instance.IReadOnlyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index 36ac12fd31f83d..8d1f02b4e62e11 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -32,55 +32,55 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, binderOptions: null); } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -88,73 +88,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index 02fb06957bb3d5..f3008878ca3c56 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -32,19 +32,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -52,73 +52,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 4703980996b889..19b955b6ea8bff 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -32,19 +32,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); } #endregion IConfiguration extensions. @@ -52,73 +52,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index 99371296997168..8533828221175b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -32,19 +32,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -52,73 +52,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index 3e6ce1459b289a..4acbebff935bca 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -67,94 +67,94 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var obj = new Program.MyClass(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass(); + BindCore(configuration, ref instance, binderOptions); + return instance; } else if (type == typeof(Program.MyClass2)) { - var obj = new Program.MyClass2(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass2(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) { var temp2 = new List(); BindCore(configuration, ref temp2, binderOptions); - int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp2.Count); - temp2.CopyTo(obj, originalCount); + int originalCount = instance.Length; + Array.Resize(ref instance, originalCount + temp2.Count); + temp2.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value5) { - obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) { - List? temp8 = obj.MyList; + List? temp8 = instance.MyList; temp8 ??= new List(); BindCore(section6, ref temp8, binderOptions); - obj.MyList = temp8; + instance.MyList = temp8; } if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section9) { - int[]? temp11 = obj.MyArray; + int[]? temp11 = instance.MyArray; temp11 ??= new int[0]; BindCore(section9, ref temp11, binderOptions); - obj.MyArray = temp11; + instance.MyArray = temp11; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section12) { - Dictionary? temp14 = obj.MyDictionary; + Dictionary? temp14 = instance.MyDictionary; temp14 ??= new Dictionary(); BindCore(section12, ref temp14, binderOptions); - obj.MyDictionary = temp14; + instance.MyDictionary = temp14; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value15) { - obj.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index 85d0901de3ff60..fb5cf5e4b5ca31 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -54,78 +54,78 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var obj = new Program.MyClass(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) { var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); - int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp1.Count); - temp1.CopyTo(obj, originalCount); + int originalCount = instance.Length; + Array.Resize(ref instance, originalCount + temp1.Count); + temp1.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp10 = obj.MyArray; + int[]? temp10 = instance.MyArray; temp10 ??= new int[0]; BindCore(section8, ref temp10, binderOptions); - obj.MyArray = temp10; + instance.MyArray = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index d394cc7b269f74..ac8e362b4e2e07 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -54,78 +54,78 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var obj = new Program.MyClass(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) { var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); - int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp1.Count); - temp1.CopyTo(obj, originalCount); + int originalCount = instance.Length; + Array.Resize(ref instance, originalCount + temp1.Count); + temp1.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp10 = obj.MyArray; + int[]? temp10 = instance.MyArray; temp10 ??= new int[0]; BindCore(section8, ref temp10, binderOptions); - obj.MyArray = temp10; + instance.MyArray = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt index 83cd88561310ab..5d0088b908162d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt @@ -54,21 +54,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass2)) { - var obj = new Program.MyClass2(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass2(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 91714c80cd0136..9da3a3a22e9b7c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -54,21 +54,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass2)) { - var obj = new Program.MyClass2(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass2(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index 88b35037c22c3f..96e389be895602 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -34,7 +34,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region OptionsBuilder extensions. /// Registers the dependency injection container to bind against the obtained from the DI service provider. [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] - public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureOptions = null) where TOptions : class + public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureBinder = null) where TOptions : class { if (optionsBuilder is null) { @@ -46,20 +46,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(configSectionPath)); } - optionsBuilder.Configure((obj, configuration) => + optionsBuilder.Configure((instance, config) => { - if (obj is null) + if (config is null) { - throw new ArgumentNullException(nameof(obj)); + throw new ArgumentNullException(nameof(config)); } - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); - BindCoreMain(section, obj, typeof(TOptions), configureOptions); + IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? config : config.GetSection(configSectionPath); + BindCoreMain(section, instance, typeof(TOptions), configureBinder); }); optionsBuilder.Services.AddSingleton, ConfigurationChangeTokenSource>(); @@ -70,16 +65,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -91,7 +81,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -99,34 +89,34 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp5 = obj.MyList; + List? temp5 = instance.MyList; temp5 ??= new List(); BindCore(section3, ref temp5, binderOptions); - obj.MyList = temp5; + instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index ff590d8398f3a1..9755ab0df00086 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -34,57 +34,52 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration) where TOptions : class + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config) where TOptions : class { - return Bind(optionsBuilder, configuration, configureOptions: null); + return Bind(optionsBuilder, config, configureBinder: null); } /// Registers a configuration instance which will bind against. - public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { if (optionsBuilder is null) { throw new ArgumentNullException(nameof(optionsBuilder)); } - Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + Configure(optionsBuilder.Services, optionsBuilder.Name, config, configureBinder); return optionsBuilder; } #endregion OptionsBuilder extensions. #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) { throw new ArgumentNullException(nameof(services)); } - if (configuration is null) + if (config is null) { - throw new ArgumentNullException(nameof(configuration)); + throw new ArgumentNullException(nameof(config)); } OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -96,7 +91,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -104,34 +99,34 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp5 = obj.MyList; + List? temp5 = instance.MyList; temp5 ??= new List(); BindCore(section3, ref temp5, binderOptions); - obj.MyList = temp5; + instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index b7b6ef86a4c056..141d2d41f77f83 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -34,51 +34,46 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { if (optionsBuilder is null) { throw new ArgumentNullException(nameof(optionsBuilder)); } - Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + Configure(optionsBuilder.Services, optionsBuilder.Name, config, configureBinder); return optionsBuilder; } #endregion OptionsBuilder extensions. #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) { throw new ArgumentNullException(nameof(services)); } - if (configuration is null) + if (config is null) { - throw new ArgumentNullException(nameof(configuration)); + throw new ArgumentNullException(nameof(config)); } OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -90,7 +85,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -98,34 +93,34 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp5 = obj.MyList; + List? temp5 = instance.MyList; temp5 ??= new List(); BindCore(section3, ref temp5, binderOptions); - obj.MyList = temp5; + instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 1bf110454ec7ba..1fd82a86d72c0d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -32,19 +32,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - if (obj is null) + if (instance is null) { - throw new ArgumentNullException(nameof(obj)); + return; } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -52,142 +52,142 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); if (configuration["Prop0"] is string value0) { - obj.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); + instance.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); } if (configuration["Prop1"] is string value1) { - obj.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); + instance.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); } if (configuration["Prop2"] is string value2) { - obj.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); + instance.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); } if (configuration["Prop3"] is string value3) { - obj.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); + instance.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); } if (configuration["Prop4"] is string value4) { - obj.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); + instance.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); } - obj.Prop5 = configuration["Prop5"]!; + instance.Prop5 = configuration["Prop5"]!; if (configuration["Prop6"] is string value6) { - obj.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); + instance.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); } if (configuration["Prop8"] is string value7) { - obj.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); + instance.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); } if (configuration["Prop9"] is string value8) { - obj.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); + instance.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); } if (configuration["Prop10"] is string value9) { - obj.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); + instance.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); } if (configuration["Prop13"] is string value10) { - obj.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); + instance.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); } if (configuration["Prop14"] is string value11) { - obj.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); + instance.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); } if (configuration["Prop15"] is string value12) { - obj.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); + instance.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); } - obj.Prop16 = configuration["Prop16"]!; + instance.Prop16 = configuration["Prop16"]!; if (configuration["Prop17"] is string value14) { - obj.Prop17 = ParseCultureInfo(value14, () => configuration.GetSection("Prop17").Path); + instance.Prop17 = ParseCultureInfo(value14, () => configuration.GetSection("Prop17").Path); } if (configuration["Prop19"] is string value15) { - obj.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); + instance.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); } if (configuration["Prop20"] is string value16) { - obj.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); + instance.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); } if (configuration["Prop21"] is string value17) { - obj.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); + instance.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); } if (configuration["Prop23"] is string value18) { - obj.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); + instance.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); } if (configuration["Prop24"] is string value19) { - obj.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); + instance.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); } if (configuration["Prop25"] is string value20) { - obj.Prop25 = ParseUri(value20, () => configuration.GetSection("Prop25").Path); + instance.Prop25 = ParseUri(value20, () => configuration.GetSection("Prop25").Path); } if (configuration["Prop26"] is string value21) { - obj.Prop26 = ParseVersion(value21, () => configuration.GetSection("Prop26").Path); + instance.Prop26 = ParseVersion(value21, () => configuration.GetSection("Prop26").Path); } if (configuration["Prop27"] is string value22) { - obj.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); + instance.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); } if (configuration["Prop7"] is string value23) { - obj.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); + instance.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); } if (configuration["Prop11"] is string value24) { - obj.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); + instance.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); } if (configuration["Prop12"] is string value25) { - obj.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); + instance.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); } if (configuration["Prop18"] is string value26) { - obj.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); + instance.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); } if (configuration["Prop22"] is string value27) { - obj.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); + instance.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 7a956f99b57b13..0ff2de59156df9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -33,27 +33,27 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config) where TOptions : class { - return Configure(services, string.Empty, configuration, configureOptions: null); + return Configure(services, string.Empty, config, configureOptions: null); } /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) { throw new ArgumentNullException(nameof(services)); } - if (configuration is null) + if (config is null) { - throw new ArgumentNullException(nameof(configuration)); + throw new ArgumentNullException(nameof(config)); } OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -61,16 +61,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -82,7 +77,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -90,81 +85,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index 399f6ffe35b935..7058edb884007f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -33,27 +33,27 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config, Action? configureOptions) where TOptions : class { - return Configure(services, string.Empty, configuration, configureOptions); + return Configure(services, string.Empty, config, configureOptions); } /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) { throw new ArgumentNullException(nameof(services)); } - if (configuration is null) + if (config is null) { - throw new ArgumentNullException(nameof(configuration)); + throw new ArgumentNullException(nameof(config)); } OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -61,16 +61,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -82,7 +77,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -90,81 +85,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index 197e268561f7eb..a8f247779978ca 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -33,27 +33,27 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config) where TOptions : class { - return Configure(services, name, configuration, configureOptions: null); + return Configure(services, name, config, configureOptions: null); } /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) { throw new ArgumentNullException(nameof(services)); } - if (configuration is null) + if (config is null) { - throw new ArgumentNullException(nameof(configuration)); + throw new ArgumentNullException(nameof(config)); } OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -61,16 +61,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -82,7 +77,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -90,81 +85,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 0cb5881950dee3..0cbd2fba049558 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -33,21 +33,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) { throw new ArgumentNullException(nameof(services)); } - if (configuration is null) + if (config is null) { - throw new ArgumentNullException(nameof(configuration)); + throw new ArgumentNullException(nameof(config)); } OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions), configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -55,16 +55,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - if (configuration is null) + if (instance is null) { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); + return; } if (!HasValueOrChildren(configuration)) @@ -76,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -84,81 +79,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 68f8a66612e67f..33a4d04834b57a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -253,9 +253,9 @@ public class MyClass2 { } Assert.Single(r); string generatedSource = string.Join('\n', r[0].SourceText.Lines.Select(x => x.ToString())); - Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? obj)", generatedSource); - Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? obj, Action? configureOptions)", generatedSource); - Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? obj)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? instance)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? instance, Action? configureOptions)", generatedSource); + Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? instance)", generatedSource); Assert.Empty(d); } diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs index 95cee559072f07..8c76472a2c339b 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/Common/ConfigurationExtensionsTests.cs @@ -12,6 +12,61 @@ public partial class ConfigurationExtensionsTests { private static IConfiguration s_emptyConfig { get; } = new ConfigurationBuilder().Build(); + [Fact] + public void TestNullHandling_OptionsBuilderExt_Bind() + { + // Null options builder. + OptionsBuilder? optionsBuilder = null; + Assert.Throws(() => optionsBuilder!.Bind(s_emptyConfig)); + Assert.Throws(() => optionsBuilder!.Bind(s_emptyConfig, _ => { })); + + // Null configuration. + optionsBuilder = CreateOptionsBuilder(); + Assert.Throws(() => optionsBuilder.Bind(config: null!)); + Assert.Throws(() => optionsBuilder.Bind(config: null!, _ => { })); + + // Null configureBinder. + optionsBuilder.Bind(s_emptyConfig, configureBinder: null); + } + + [Fact] + public void TestNullHandling_OptionsBuilderExt_BindConfiguration() + { + // Null options builder. + string configSectionPath = "FakeSectionPath"; + OptionsBuilder? optionsBuilder = null; + Assert.Throws(() => optionsBuilder!.BindConfiguration(configSectionPath)); + + // Null config section path. + optionsBuilder = CreateOptionsBuilder(); + Assert.Throws(() => optionsBuilder.BindConfiguration(configSectionPath: null!)); + + // Null configureBinder. + optionsBuilder.BindConfiguration(configSectionPath, configureBinder: null); + } + + [Fact] + public void TestNullHandling_IServiceCollectionExt_Configure() + { + // Null services + IServiceCollection? services = null; + string name = "Name"; + Assert.Throws(() => services!.Configure(s_emptyConfig)); + Assert.Throws(() => services!.Configure(name, s_emptyConfig)); + + // Null config. + services = new ServiceCollection(); + Assert.Throws(() => services.Configure(config: null!)); + Assert.Throws(() => services.Configure(name, config: null!)); + + // Null name. + services.Configure(name: null!, s_emptyConfig); + + // Null configureBinder. + services.Configure(s_emptyConfig, configureBinder: null); + services.Configure(name, s_emptyConfig, configureBinder: null); + } + private static OptionsBuilder CreateOptionsBuilder() { var services = new ServiceCollection(); diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/UnitTests/Microsoft.Extensions.Options.ConfigurationExtensions.UnitTests.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/UnitTests/Microsoft.Extensions.Options.ConfigurationExtensions.UnitTests.csproj index 3a5db72bf30f7d..512e0018a400c0 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/UnitTests/Microsoft.Extensions.Options.ConfigurationExtensions.UnitTests.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/UnitTests/Microsoft.Extensions.Options.ConfigurationExtensions.UnitTests.csproj @@ -16,10 +16,11 @@ + - + \ No newline at end of file From 9c422ed36a6f68a1940cc737d4a173bafd27467c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:26:43 -0700 Subject: [PATCH 121/345] [release/8.0] Fix nullable annotation for Validator.TryValidateValue and ValidateValue (#91293) * Fix nullable annotation for Validator.TryValidateValue and ValidateValue * Revert Options source generator nullable annotation changes for Validator.TryValidateValue (#91305) * Fix nullable annotation for Validator.ValidateValue ref source (#91351) --------- Co-authored-by: Jeff Handley --- .../ref/System.ComponentModel.Annotations.cs | 4 ++-- .../System/ComponentModel/DataAnnotations/Validator.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs b/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs index 542845070d0c38..c9e82b8cece0c7 100644 --- a/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs +++ b/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs @@ -387,14 +387,14 @@ public static partial class Validator public static bool TryValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection? validationResults, bool validateAllProperties) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of validationContext.ObjectType cannot be statically discovered.")] public static bool TryValidateProperty(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection? validationResults) { throw null; } - public static bool TryValidateValue(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection? validationResults, System.Collections.Generic.IEnumerable validationAttributes) { throw null; } + public static bool TryValidateValue(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection? validationResults, System.Collections.Generic.IEnumerable validationAttributes) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered and the Type's properties can be trimmed.")] public static void ValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered and the Type's properties can be trimmed.")] public static void ValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext, bool validateAllProperties) { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of validationContext.ObjectType cannot be statically discovered.")] public static void ValidateProperty(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { } - public static void ValidateValue(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.IEnumerable validationAttributes) { } + public static void ValidateValue(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.IEnumerable validationAttributes) { } } } namespace System.ComponentModel.DataAnnotations.Schema diff --git a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Validator.cs b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Validator.cs index 3913a1df4c3fe7..d6719673011117 100644 --- a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Validator.cs +++ b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Validator.cs @@ -171,7 +171,7 @@ public static bool TryValidateObject(object instance, ValidationContext validati /// then all validators will be evaluated. /// /// - /// The value to test. It cannot be null. + /// The value to test. /// /// Describes the object being validated and provides services and context for the /// validators. @@ -182,7 +182,7 @@ public static bool TryValidateObject(object instance, ValidationContext validati /// against. /// /// true if the object is valid, false if any validation errors are encountered. - public static bool TryValidateValue(object value, ValidationContext validationContext, + public static bool TryValidateValue(object? value, ValidationContext validationContext, ICollection? validationResults, IEnumerable validationAttributes) { ArgumentNullException.ThrowIfNull(validationAttributes); @@ -303,12 +303,12 @@ public static void ValidateObject(object instance, ValidationContext validationC /// first. /// /// - /// The value to test. It cannot be null. + /// The value to test. /// Describes the object being tested. /// The list of s to validate against this instance. /// When is null. /// When is found to be invalid. - public static void ValidateValue(object value, ValidationContext validationContext, + public static void ValidateValue(object? value, ValidationContext validationContext, IEnumerable validationAttributes) { ArgumentNullException.ThrowIfNull(validationContext); From 399f37c6812f71066d944c5319164126def16204 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:27:06 -0700 Subject: [PATCH 122/345] [release/8.0] [DependencyInjection] introduce feature switch to disable S.R.E (#91352) * [DependencyInjection] introduce feature switch to disable S.R.E When recording a new AOT profile for .NET MAUI apps running on Android, we noticed that System.Reflection.Emit work was being done on a background thread. The call seen in `dotnet-trace` output: 11.32ms microsoft.extensions.dependencyinjection!Microsoft.Extensions.DependencyInjection.ServiceLookup.ILEmitResolverBuilder.GenerateMethodBody(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite,System.Reflection.Emit.ILGenerator) .NET Android apps are unique in that there is a JIT, `RuntimeFeature.IsDynamicCodeCompiled` is true, System.Reflection.Emit is possible -- S.R.E is however, not great for startup performance. Starting threads on Android during startup can also be slow, as Android will commonly put all but a single core to sleep for battery saving purposes. We try to avoid starting threads on startup for "hello world" applications on Android. To solve this for now, introduce a new feature flag: Microsoft.Extensions.DependencyInjection.DisableDynamicEngine Which, we will provide a value in either the Android or .NET MAUI optional workload via an MSBuild property. To test, I put this in my app's `.csproj` file: Customers *could* opt to change this flag, but we don't think it will particularly useful. An example of services realized by .NET MAUI at startup, via some logging added: 08-25 13:21:55.647 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.IMauiInitializeService] 08-25 13:21:55.664 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.IMauiInitializeScopedService] 08-25 13:21:55.665 16530 16530 I DOTNET : RealizeService called: Microsoft.Maui.Dispatching.IDispatcher 08-25 13:21:55.668 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.LifecycleEvents.LifecycleEventRegistration] 08-25 13:21:56.057 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.HandlerMauiAppBuilderExtensions+HandlerRegistration] 08-25 13:21:56.115 16530 16530 I DOTNET : RealizeService called: Microsoft.Extensions.DependencyInjection.IServiceScopeFactory 08-25 13:21:56.670 16530 16530 I DOTNET : RealizeService called: Microsoft.Maui.Controls.HideSoftInputOnTappedChangedManager 08-25 13:21:56.712 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.ImageSourcesMauiAppBuilderExtensions+ImageSourceRegistration] 08-25 13:21:57.700 16530 16530 I DOTNET : RealizeService using S.R.E: Microsoft.Maui.Controls.HideSoftInputOnTappedChangedManager `HideSoftInputOnTappedChangedManager` would be realized once per page, which would not be a huge payoff to use S.R.E for. So the only way the S.R.E codepath could be useful on Android would be if the customer is registering lots of services themselves. They might be better off just using `new()` in that case? An example of the startup time Android reports with the new flag on/off: DisableDynamicEngine=false 08-25 14:31:37.462 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +733ms 08-25 14:31:39.394 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +737ms 08-25 14:31:41.326 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +730ms DisableDynamicEngine=true 08-25 14:32:20.233 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +724ms 08-25 14:32:22.137 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +727ms 08-25 14:32:24.042 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +716ms This was a `dotnet new maui` project, using dotnet/maui/main on a Pixel 5 device. * Update docs/workflow/trimming/feature-switches.md Co-authored-by: Eric Erhardt --------- Co-authored-by: Jonathan Peppers Co-authored-by: Jonathan Peppers Co-authored-by: Eric Erhardt --- docs/workflow/trimming/feature-switches.md | 1 + .../src/ILLink/ILLink.Substitutions.xml | 3 +++ .../src/ServiceProvider.cs | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/workflow/trimming/feature-switches.md b/docs/workflow/trimming/feature-switches.md index 87d8fa4c5ec425..7fa3045547e0f0 100644 --- a/docs/workflow/trimming/feature-switches.md +++ b/docs/workflow/trimming/feature-switches.md @@ -27,6 +27,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif | MetadataUpdaterSupport | System.Reflection.Metadata.MetadataUpdater.IsSupported | Metadata update related code to be trimmed when set to false | | _EnableConsumingManagedCodeFromNativeHosting | System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting | Getting a managed function from native hosting is disabled when set to false and related functionality can be trimmed. | | VerifyDependencyInjectionOpenGenericServiceTrimmability | Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability | When set to true, DependencyInjection will verify trimming annotations applied to open generic services are correct | +| DisableDependencyInjectionDynamicEngine | Microsoft.Extensions.DependencyInjection.DisableDynamicEngine | When set to true, DependencyInjection will avoid using System.Reflection.Emit when realizing services | | NullabilityInfoContextSupport | System.Reflection.NullabilityInfoContext.IsSupported | Nullable attributes can be trimmed when set to false | | DynamicCodeSupport | System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported | Changes RuntimeFeature.IsDynamicCodeSupported to false to allow testing AOT-safe fallback code without publishing for Native AOT. | | _AggressiveAttributeTrimming | System.AggressiveAttributeTrimming | When set to true, aggressively trims attributes to allow for the most size savings possible, even if it could result in runtime behavior changes | diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ILLink/ILLink.Substitutions.xml b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ILLink/ILLink.Substitutions.xml index eb381de19d6153..6aa354ee23683c 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ILLink/ILLink.Substitutions.xml +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ILLink/ILLink.Substitutions.xml @@ -3,5 +3,8 @@ + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs index aa178741fc4516..ff5efbe98cf334 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs @@ -37,6 +37,9 @@ public sealed class ServiceProvider : IServiceProvider, IKeyedServiceProvider, I internal static bool VerifyOpenGenericServiceTrimmability { get; } = AppContext.TryGetSwitch("Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability", out bool verifyOpenGenerics) ? verifyOpenGenerics : false; + internal static bool DisableDynamicEngine { get; } = + AppContext.TryGetSwitch("Microsoft.Extensions.DependencyInjection.DisableDynamicEngine", out bool disableDynamicEngine) ? disableDynamicEngine : false; + internal static bool VerifyAotCompatibility => #if NETFRAMEWORK || NETSTANDARD2_0 false; @@ -246,7 +249,7 @@ private ServiceProviderEngine GetEngine() #if NETFRAMEWORK || NETSTANDARD2_0 engine = CreateDynamicEngine(); #else - if (RuntimeFeature.IsDynamicCodeCompiled) + if (RuntimeFeature.IsDynamicCodeCompiled && !DisableDynamicEngine) { engine = CreateDynamicEngine(); } From cd8b2cb89f51c6e780e868f27fe0fd8ef43454d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:24:29 -0600 Subject: [PATCH 123/345] [release/8.0] [Mono] Fix offset calculation for nested struct, when pinvoke is enabled (#91417) * Fix offset calculation for nested struct * Add a test for nested struct with pinvoke * Move and update test with real c++ implementation * Exclude newly added test from wasm * Disable interop tests on android and apple devices --------- Co-authored-by: Fan Yang --- src/mono/mono/mini/mini-amd64.c | 4 +- .../PInvoke/GameControllerButtonBind.cs | 63 +++++++++++++++++++ .../PInvoke/MarshalStructAsParamDLL.cpp | 5 ++ .../PInvoke/MarshalStructAsParamDLL.h | 23 +++++++ .../StructMarshalling/PInvoke/NestedStruct.cs | 27 ++++++++ .../PInvoke/NestedStruct.csproj | 14 +++++ src/tests/issues.targets | 12 ++++ 7 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs create mode 100644 src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs create mode 100644 src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 1a2f9fff59d34e..e03b142feef1f3 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -357,7 +357,7 @@ collect_field_info_nested (MonoClass *klass, GArray *fields_array, int offset, g g_assert(info); for (guint32 i = 0; i < info->num_fields; ++i) { if (MONO_TYPE_ISSTRUCT (info->fields [i].field->type)) { - collect_field_info_nested (mono_class_from_mono_type_internal (info->fields [i].field->type), fields_array, info->fields [i].offset, pinvoke, unicode); + collect_field_info_nested (mono_class_from_mono_type_internal (info->fields [i].field->type), fields_array, (offset + info->fields [i].offset), pinvoke, unicode); } else { guint32 align; StructFieldInfo f; @@ -367,7 +367,7 @@ collect_field_info_nested (MonoClass *klass, GArray *fields_array, int offset, g info->fields [i].mspec, &align, TRUE, unicode); f.offset = offset + info->fields [i].offset; - if (i == info->num_fields - 1 && f.size + f.offset < info->native_size) { + if ((i == info->num_fields - 1) && ((f.size + f.offset) < info->native_size)) { /* This can happen with .pack directives eg. 'fixed' arrays */ if (MONO_TYPE_IS_PRIMITIVE (f.type)) { /* Replicate the last field to fill out the remaining place, since the code in add_valuetype () needs type information */ diff --git a/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs b/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs new file mode 100644 index 00000000000000..a65994f2307a3f --- /dev/null +++ b/src/tests/Interop/StructMarshalling/PInvoke/GameControllerButtonBind.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Text; + +public unsafe partial struct GameControllerButtonBind +{ + public GameControllerButtonBind + ( + GameControllerBindType? bindType = null, + GameControllerButtonBindValue? value = null + ) : this() + { + if (bindType is not null) + { + BindType = bindType.Value; + } + + if (value is not null) + { + Value = value.Value; + } + } + + public GameControllerBindType BindType; + + public GameControllerButtonBindValue Value; +} + +public enum GameControllerBindType : int +{ + ControllerBindtypeNone = 0x0, + ControllerBindtypeButton = 0x1, + ControllerBindtypeAxis = 0x2, + ControllerBindtypeHat = 0x3, + None = 0x0, + Button = 0x1, + Axis = 0x2, + Hat = 0x3, +} + +[StructLayout(LayoutKind.Explicit)] +public unsafe partial struct GameControllerButtonBindValue +{ + [FieldOffset(0)] + public int Button; + + [FieldOffset(0)] + public int Axis; + + [FieldOffset(0)] + public GameControllerButtonBindValueHat Hat; +} + +public unsafe partial struct GameControllerButtonBindValueHat +{ + public int Hat; + + public int HatMask; +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp index 9278650d20dce8..e19eec7feb0737 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp @@ -1297,3 +1297,8 @@ extern "C" DLL_EXPORT Int32CLongStruct STDMETHODCALLTYPE AddCLongs(Int32CLongStr { return { lhs.i + rhs.i, lhs.l + rhs.l }; } + +extern "C" DLL_EXPORT SDL_GameControllerBindType STDMETHODCALLTYPE getBindType(SDL_GameControllerButtonBind button) +{ + return button.bindType; +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h index c85b1e6f62dc05..17844b8c365263 100644 --- a/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h +++ b/src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h @@ -974,3 +974,26 @@ struct Int32CLongStruct int32_t i; long l; }; + +typedef enum +{ + SDL_CONTROLLER_BINDTYPE_NONE = 0, + SDL_CONTROLLER_BINDTYPE_BUTTON, + SDL_CONTROLLER_BINDTYPE_AXIS, + SDL_CONTROLLER_BINDTYPE_HAT +} SDL_GameControllerBindType; + +typedef struct SDL_GameControllerButtonBind +{ + SDL_GameControllerBindType bindType; + union + { + int button; + int axis; + struct { + int hat; + int hat_mask; + } hat; + } value; + +} SDL_GameControllerButtonBind; diff --git a/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs new file mode 100644 index 00000000000000..870e75bff62525 --- /dev/null +++ b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Xunit; + +public class Managed +{ + [DllImport("MarshalStructAsParam")] + static extern GameControllerBindType getBindType (GameControllerButtonBind button); + + public static int Main() + { + GameControllerButtonBind button = new GameControllerButtonBind(GameControllerBindType.ControllerBindtypeAxis, null); + if (getBindType(button) == GameControllerBindType.ControllerBindtypeAxis) + { + Console.WriteLine("\nTEST PASSED!"); + return 100; + } + else + { + Console.WriteLine("\nTEST FAILED!"); + return 1; + } + } +} diff --git a/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj new file mode 100644 index 00000000000000..0b0d4aa0836435 --- /dev/null +++ b/src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj @@ -0,0 +1,14 @@ + + + exe + true + + + + + + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index e9485d290e2d5d..7ec7dc726f34ef 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2939,6 +2939,9 @@ https://github.com/dotnet/runtime/issues/64127 + + https://github.com/dotnet/runtime/issues/64127 + https://github.com/dotnet/runtime/issues/64127 @@ -3492,6 +3495,15 @@ https://github.com/dotnet/runtime/issues/67359 + + https://github.com/dotnet/runtime/issues/91388 + + + https://github.com/dotnet/runtime/issues/91388 + + + https://github.com/dotnet/runtime/issues/91388 + From ee2405677e1eb5c91d46cd58d2aa04b9506e2296 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:30:15 -0600 Subject: [PATCH 124/345] [release/8.0] Options Source Gen Fixes (#91432) * Options Source Gen Fixes * Remove unnecessary interpolated string usage * Address the feedback * Remove repeated word in the comment --------- Co-authored-by: Tarek Mahmoud Sayed --- .../gen/Emitter.cs | 85 ++- ...Extensions.Options.SourceGeneration.csproj | 1 + .../gen/Parser.cs | 7 + .../gen/SymbolHolder.cs | 5 +- .../gen/SymbolLoader.cs | 27 +- .../tests/SourceGeneration.Unit.Tests/Main.cs | 17 +- .../OptionsRuntimeTests.cs | 45 +- .../Baselines/NetCoreApp/Validators.g.cs | 658 ++++++++---------- .../Baselines/NetFX/Validators.g.cs | 658 ++++++++---------- 9 files changed, 740 insertions(+), 763 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs index adbaa874ad7f37..9e0cb659a6c94a 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; namespace Microsoft.Extensions.Options.Generators { @@ -25,6 +27,7 @@ internal sealed class Emitter : EmitterBase private string _staticValidationAttributeHolderClassFQN; private string _staticValidatorHolderClassFQN; private string _modifier; + private string _TryGetValueNullableAnnotation; private sealed record StaticFieldInfo(string FieldTypeFQN, int FieldOrder, string FieldName, IList InstantiationLines); @@ -37,13 +40,14 @@ public Emitter(Compilation compilation, bool emitPreamble = true) : base(emitPre else { _modifier = "internal"; - string suffix = $"_{new Random().Next():X8}"; + string suffix = $"_{GetNonRandomizedHashCode(compilation.SourceModule.Name):X8}"; _staticValidationAttributeHolderClassName += suffix; _staticValidatorHolderClassName += suffix; } _staticValidationAttributeHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{_staticValidationAttributeHolderClassName}"; _staticValidatorHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{_staticValidatorHolderClassName}"; + _TryGetValueNullableAnnotation = GetNullableAnnotationStringForTryValidateValueToUseInGeneratedCode(compilation); } public string Emit( @@ -65,6 +69,31 @@ public string Emit( return Capture(); } + /// + /// Returns the nullable annotation string to use in the code generation according to the first parameter of + /// is nullable annotated. + /// + /// The to consider for analysis. + /// "!" if the first parameter is not nullable annotated, otherwise an empty string. + /// + /// In .NET 8.0 we have changed the nullable annotation on first parameter of the method cref="System.ComponentModel.DataAnnotations.Validator.TryValidateValue(object, ValidationContext, ICollection{ValidationResult}, IEnumerable{ValidationAttribute})"/> + /// The source generator need to detect if we need to append "!" to the first parameter of the method call when running on down-level versions. + /// + private static string GetNullableAnnotationStringForTryValidateValueToUseInGeneratedCode(Compilation compilation) + { + INamedTypeSymbol? validatorTypeSymbol = compilation.GetBestTypeByMetadataName("System.ComponentModel.DataAnnotations.Validator"); + if (validatorTypeSymbol is not null) + { + ImmutableArray members = validatorTypeSymbol.GetMembers("TryValidateValue"); + if (members.Length == 1 && members[0] is IMethodSymbol tryValidateValueMethod) + { + return tryValidateValueMethod.Parameters[0].NullableAnnotation == NullableAnnotation.NotAnnotated ? "!" : string.Empty; + } + } + + return "!"; + } + private void GenValidatorType(ValidatorType vt, ref Dictionary staticValidationAttributesDict, ref Dictionary staticValidatorsDict) { if (vt.Namespace.Length > 0) @@ -161,7 +190,7 @@ private void GenModelSelfValidationIfNecessary(ValidatedModel modelToValidate) { if (modelToValidate.SelfValidates) { - OutLn($"builder.AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context));"); + OutLn($"(builder ??= new()).AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context));"); OutLn(); } } @@ -182,8 +211,7 @@ private void GenModelValidationMethod( OutLn($"public {(makeStatic ? "static " : string.Empty)}global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, {modelToValidate.Name} options)"); OutOpenBrace(); - OutLn($"var baseName = (string.IsNullOrEmpty(name) ? \"{modelToValidate.SimpleName}\" : name) + \".\";"); - OutLn($"var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder();"); + OutLn($"global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;"); OutLn($"var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);"); int capacity = modelToValidate.MembersToValidate.Max(static vm => vm.ValidationAttributes.Count); @@ -199,33 +227,33 @@ private void GenModelValidationMethod( { if (vm.ValidationAttributes.Count > 0) { - GenMemberValidation(vm, ref staticValidationAttributesDict, cleanListsBeforeUse); + GenMemberValidation(vm, modelToValidate.SimpleName, ref staticValidationAttributesDict, cleanListsBeforeUse); cleanListsBeforeUse = true; OutLn(); } if (vm.TransValidatorType is not null) { - GenTransitiveValidation(vm, ref staticValidatorsDict); + GenTransitiveValidation(vm, modelToValidate.SimpleName, ref staticValidatorsDict); OutLn(); } if (vm.EnumerationValidatorType is not null) { - GenEnumerationValidation(vm, ref staticValidatorsDict); + GenEnumerationValidation(vm, modelToValidate.SimpleName, ref staticValidatorsDict); OutLn(); } } GenModelSelfValidationIfNecessary(modelToValidate); - OutLn($"return builder.Build();"); + OutLn($"return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build();"); OutCloseBrace(); } - private void GenMemberValidation(ValidatedMember vm, ref Dictionary staticValidationAttributesDict, bool cleanListsBeforeUse) + private void GenMemberValidation(ValidatedMember vm, string modelName, ref Dictionary staticValidationAttributesDict, bool cleanListsBeforeUse) { OutLn($"context.MemberName = \"{vm.Name}\";"); - OutLn($"context.DisplayName = baseName + \"{vm.Name}\";"); + OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"{modelName}.{vm.Name}\" : $\"{{name}}.{vm.Name}\";"); if (cleanListsBeforeUse) { @@ -239,9 +267,9 @@ private void GenMemberValidation(ValidatedMember vm, ref Dictionary staticValidatorsDict) + private void GenTransitiveValidation(ValidatedMember vm, string modelName, ref Dictionary staticValidatorsDict) { string callSequence; if (vm.TransValidateTypeIsSynthetic) @@ -321,20 +349,22 @@ private void GenTransitiveValidation(ValidatedMember vm, ref Dictionary staticValidatorsDict) + private void GenEnumerationValidation(ValidatedMember vm, string modelName, ref Dictionary staticValidatorsDict) { var valueAccess = (vm.IsValueType && vm.IsNullable) ? ".Value" : string.Empty; var enumeratedValueAccess = (vm.EnumeratedIsNullable && vm.EnumeratedIsValueType) ? ".Value" : string.Empty; @@ -365,14 +395,16 @@ private void GenEnumerationValidation(ValidatedMember vm, ref Dictionary + /// Returns a non-randomized hash code for the given string. + /// We always return a positive value. + /// + internal static int GetNonRandomizedHashCode(string s) + { + uint result = 2166136261u; + foreach (char c in s) + { + result = (c ^ result) * 16777619; + } + return Math.Abs((int)result); + } } } diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj index 41ceaf6739c333..5571341b06060e 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Options/gen/Microsoft.Extensions.Options.SourceGeneration.csproj @@ -20,6 +20,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs b/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs index 0c8e216e488c7f..1ecd82cbe74c07 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/Parser.cs @@ -240,6 +240,13 @@ private static bool HasOpenGenerics(ITypeSymbol type, out string genericType) type = ((INamedTypeSymbol)type).TypeArguments[0]; } + // Check first if the type is IEnumerable interface + if (SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, _symbolHolder.GenericIEnumerableSymbol)) + { + return ((INamedTypeSymbol)type).TypeArguments[0]; + } + + // Check first if the type implement IEnumerable interface foreach (var implementingInterface in type.AllInterfaces) { if (SymbolEqualityComparer.Default.Equals(implementingInterface.OriginalDefinition, _compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T))) diff --git a/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs b/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs index c78106e1bc4a27..55d382e4036219 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/SymbolHolder.cs @@ -14,7 +14,8 @@ internal sealed record class SymbolHolder( INamedTypeSymbol DataTypeAttributeSymbol, INamedTypeSymbol ValidateOptionsSymbol, INamedTypeSymbol IValidatableObjectSymbol, + INamedTypeSymbol GenericIEnumerableSymbol, INamedTypeSymbol TypeSymbol, - INamedTypeSymbol? ValidateObjectMembersAttributeSymbol, - INamedTypeSymbol? ValidateEnumeratedItemsAttributeSymbol); + INamedTypeSymbol ValidateObjectMembersAttributeSymbol, + INamedTypeSymbol ValidateEnumeratedItemsAttributeSymbol); } diff --git a/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs b/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs index 6f805e91a05858..94035cedacbf98 100644 --- a/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs +++ b/src/libraries/Microsoft.Extensions.Options/gen/SymbolLoader.cs @@ -15,19 +15,11 @@ internal static class SymbolLoader internal const string TypeOfType = "System.Type"; internal const string ValidateObjectMembersAttribute = "Microsoft.Extensions.Options.ValidateObjectMembersAttribute"; internal const string ValidateEnumeratedItemsAttribute = "Microsoft.Extensions.Options.ValidateEnumeratedItemsAttribute"; + internal const string GenericIEnumerableType = "System.Collections.Generic.IEnumerable`1"; public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHolder) { - INamedTypeSymbol? GetSymbol(string metadataName, bool optional = false) - { - var symbol = compilation.GetTypeByMetadataName(metadataName); - if (symbol == null && !optional) - { - return null; - } - - return symbol; - } + INamedTypeSymbol? GetSymbol(string metadataName) => compilation.GetTypeByMetadataName(metadataName); // required var optionsValidatorSymbol = GetSymbol(OptionsValidatorAttribute); @@ -35,7 +27,10 @@ public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHold var dataTypeAttributeSymbol = GetSymbol(DataTypeAttribute); var ivalidatableObjectSymbol = GetSymbol(IValidatableObjectType); var validateOptionsSymbol = GetSymbol(IValidateOptionsType); + var genericIEnumerableSymbol = GetSymbol(GenericIEnumerableType); var typeSymbol = GetSymbol(TypeOfType); + var validateObjectMembersAttribute = GetSymbol(ValidateObjectMembersAttribute); + var validateEnumeratedItemsAttribute = GetSymbol(ValidateEnumeratedItemsAttribute); #pragma warning disable S1067 // Expressions should not be too complex if (optionsValidatorSymbol == null || @@ -43,7 +38,10 @@ public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHold dataTypeAttributeSymbol == null || ivalidatableObjectSymbol == null || validateOptionsSymbol == null || - typeSymbol == null) + genericIEnumerableSymbol == null || + typeSymbol == null || + validateObjectMembersAttribute == null || + validateEnumeratedItemsAttribute == null) { symbolHolder = default; return false; @@ -56,11 +54,10 @@ public static bool TryLoad(Compilation compilation, out SymbolHolder? symbolHold dataTypeAttributeSymbol, validateOptionsSymbol, ivalidatableObjectSymbol, + genericIEnumerableSymbol, typeSymbol, - - // optional - GetSymbol(ValidateObjectMembersAttribute, optional: true), - GetSymbol(ValidateEnumeratedItemsAttribute, optional: true)); + validateObjectMembersAttribute, + validateEnumeratedItemsAttribute); return true; } diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs index f3e0513a885f22..ca0db51c121024 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Main.cs @@ -70,31 +70,30 @@ partial struct MyOptionsValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::HelloWorld.MyOptions options) { - var baseName = (string.IsNullOrEmpty(name) ? "MyOptions" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs index 1ac4618014ba92..9a5de0e759f8a6 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs @@ -25,10 +25,15 @@ public void TestValidationSuccessResults() { Tall = 10, Id = "1", - Children = new() + Children1 = new() { - new ChildOptions() { Name = "C1" }, - new ChildOptions() { Name = "C2" } + new ChildOptions() { Name = "C1-1" }, + new ChildOptions() { Name = "C1-2" } + }, + Children2 = new List() + { + new ChildOptions() { Name = "C2-1" }, + new ChildOptions() { Name = "C2-2" } }, NestedList = new() { @@ -126,12 +131,19 @@ public void TestValidationWithEnumeration() { Tall = 10, Id = "1", - Children = new() + Children1 = new() { new ChildOptions(), new ChildOptions(), new ChildOptions() - } + }, + Children2 = new List() + { + new ChildOptions(), + new ChildOptions(), + new ChildOptions() + }, + } }; @@ -142,9 +154,12 @@ public void TestValidationWithEnumeration() Assert.True(result1.Failed); Assert.Equal(new List { - "Name: The MyOptions.Nested.Children[0].Name field is required.", - "Name: The MyOptions.Nested.Children[1].Name field is required.", - "Name: The MyOptions.Nested.Children[2].Name field is required.", + "Name: The MyOptions.Nested.Children1[0].Name field is required.", + "Name: The MyOptions.Nested.Children1[1].Name field is required.", + "Name: The MyOptions.Nested.Children1[2].Name field is required.", + "Name: The MyOptions.Nested.Children2[0].Name field is required.", + "Name: The MyOptions.Nested.Children2[1].Name field is required.", + "Name: The MyOptions.Nested.Children2[2].Name field is required.", }, result1.Failures); @@ -152,9 +167,12 @@ public void TestValidationWithEnumeration() Assert.True(result2.Failed); Assert.Equal(new List { - "DataAnnotation validation failed for 'MyOptions.Nested.Children[0]' members: 'Name' with the error: 'The Name field is required.'.", - "DataAnnotation validation failed for 'MyOptions.Nested.Children[1]' members: 'Name' with the error: 'The Name field is required.'.", - "DataAnnotation validation failed for 'MyOptions.Nested.Children[2]' members: 'Name' with the error: 'The Name field is required.'.", + "DataAnnotation validation failed for 'MyOptions.Nested.Children1[0]' members: 'Name' with the error: 'The Name field is required.'.", + "DataAnnotation validation failed for 'MyOptions.Nested.Children1[1]' members: 'Name' with the error: 'The Name field is required.'.", + "DataAnnotation validation failed for 'MyOptions.Nested.Children1[2]' members: 'Name' with the error: 'The Name field is required.'.", + "DataAnnotation validation failed for 'MyOptions.Nested.Children2[0]' members: 'Name' with the error: 'The Name field is required.'.", + "DataAnnotation validation failed for 'MyOptions.Nested.Children2[1]' members: 'Name' with the error: 'The Name field is required.'.", + "DataAnnotation validation failed for 'MyOptions.Nested.Children2[2]' members: 'Name' with the error: 'The Name field is required.'.", }, result2.Failures); } @@ -219,7 +237,10 @@ public class NestedOptions public string? Id { get; set; } [ValidateEnumeratedItems] - public List? Children { get; set; } + public List? Children1 { get; set; } + + [ValidateEnumeratedItems] + public IEnumerable? Children2 { get; set; } #pragma warning disable SYSLIB1211 // Source gen does static analysis for circular reference. We need to disable it for this test. [ValidateEnumeratedItems] diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs index a467ed2dd6c007..cc1ebda6414e6b 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetCoreApp/Validators.g.cs @@ -14,22 +14,21 @@ internal sealed partial class __ThirdModelNoNamespaceValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::ThirdModelNoNamespace options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModelNoNamespace" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModelNoNamespace.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } partial class FirstValidatorNoNamespace @@ -43,32 +42,31 @@ partial class FirstValidatorNoNamespace [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::FirstModelNoNamespace options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModelNoNamespace" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModelNoNamespace.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V1.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V1.Validate(string.IsNullOrEmpty(name) ? "FirstModelNoNamespace.P2" : $"{name}.P2", options.P2)); } if (options.P3 is not null) { - builder.AddResult(global::__ThirdModelNoNamespaceValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::__ThirdModelNoNamespaceValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModelNoNamespace.P3" : $"{name}.P3", options.P3)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } partial class SecondValidatorNoNamespace @@ -82,22 +80,21 @@ partial class SecondValidatorNoNamespace [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::SecondModelNoNamespace options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModelNoNamespace" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModelNoNamespace.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } namespace CustomAttr @@ -113,31 +110,30 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::CustomAttr.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A3); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "P2"; - context.DisplayName = baseName + "P2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A4); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -155,22 +151,21 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -188,21 +183,20 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Value"; - context.DisplayName = baseName + "Value"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.Value" : $"{name}.Value"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A5); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Value!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Value, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -219,8 +213,7 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); if (options.P1 is not null) @@ -230,11 +223,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P1[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P1[{count}]" : $"{name}.P1[{count}]", o)); } else { - builder.AddError(baseName + $"P1[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P1[{count}] is null" : $"{name}.P1[{count}] is null"); } count++; } @@ -247,11 +240,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V2.Validate(baseName + $"P2[{count}]", o)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V2.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P2[{count}]" : $"{name}.P2[{count}]", o)); } else { - builder.AddError(baseName + $"P2[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P2[{count}] is null" : $"{name}.P2[{count}] is null"); } count++; } @@ -264,7 +257,7 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P3[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P3[{count}]" : $"{name}.P3[{count}]", o)); } count++; } @@ -275,7 +268,7 @@ partial struct FirstValidator var count = 0; foreach (var o in options.P4) { - builder.AddResult(global::Enumeration.__ThirdModelValidator__.Validate(baseName + $"P4[{count++}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P4[{count++}] is null" : $"{name}.P4[{count++}] is null", o)); } } @@ -286,7 +279,7 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__ThirdModelValidator__.Validate(baseName + $"P5[{count}]", o.Value)); + (builder ??= new()).AddResult(global::Enumeration.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P5[{count}]" : $"{name}.P5[{count}]", o.Value)); } count++; } @@ -299,7 +292,7 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__ThirdModelValidator__.Validate(baseName + $"P51[{count}]", o.Value)); + (builder ??= new()).AddResult(global::Enumeration.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P51[{count}]" : $"{name}.P51[{count}]", o.Value)); } count++; } @@ -312,11 +305,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P6[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P6[{count}]" : $"{name}.P6[{count}]", o)); } else { - builder.AddError(baseName + $"P6[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P6[{count}] is null" : $"{name}.P6[{count}] is null"); } count++; } @@ -328,11 +321,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P7[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P7[{count}]" : $"{name}.P7[{count}]", o)); } else { - builder.AddError(baseName + $"P7[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P7[{count}] is null" : $"{name}.P7[{count}] is null"); } count++; } @@ -345,17 +338,17 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P8[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P8[{count}]" : $"{name}.P8[{count}]", o)); } else { - builder.AddError(baseName + $"P8[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P8[{count}] is null" : $"{name}.P8[{count}] is null"); } count++; } } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -372,22 +365,21 @@ partial struct SecondValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -404,22 +396,21 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::FileScopedNamespace.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -436,21 +427,20 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::FunnyStrings.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A6); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -468,22 +458,21 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Generics.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -500,27 +489,26 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Generics.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P3 is not null) { - builder.AddResult(global::Generics.__SecondModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::Generics.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -537,27 +525,26 @@ partial struct MultiValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::MultiModelValidator.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V3.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V3.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } /// /// Validates a specific named options instance (or all when is ). @@ -568,22 +555,21 @@ partial struct MultiValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::MultiModelValidator.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P3"; - context.DisplayName = baseName + "P3"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P3" : $"{name}.P3"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -601,22 +587,21 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -635,22 +620,21 @@ partial record struct FifthValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -672,34 +656,33 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V4.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V4.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } - builder.AddResult(global::Nested.__ThirdModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::Nested.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); if (options.P4 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V5.Validate(baseName + "P4", options.P4)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V5.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P4" : $"{name}.P4", options.P4)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -720,22 +703,21 @@ partial struct FourthValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -757,22 +739,21 @@ partial struct SecondValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -795,22 +776,21 @@ partial struct ThirdValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -829,22 +809,21 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RandomMembers.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -862,22 +841,21 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -894,34 +872,33 @@ partial record struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V6.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V6.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } if (options.P3 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V7.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V7.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); } - builder.AddResult(global::RecordTypes.__ThirdModelValidator__.Validate(baseName + "P4", options.P4)); + (builder ??= new()).AddResult(global::RecordTypes.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P4" : $"{name}.P4", options.P4)); - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -938,22 +915,21 @@ partial record struct SecondValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -970,22 +946,21 @@ partial record class ThirdValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1003,26 +978,25 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RepeatedTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P4 is not null) { - builder.AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(baseName + "P4", options.P4)); + (builder ??= new()).AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4", options.P4)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1040,22 +1014,21 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RepeatedTypes.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1072,56 +1045,55 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RepeatedTypes.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P1 is not null) { - builder.AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(baseName + "P1", options.P1)); + (builder ??= new()).AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1", options.P1)); } context.MemberName = "P2"; - context.DisplayName = baseName + "P2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } context.MemberName = "P3"; - context.DisplayName = baseName + "P3"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P3 is not null) { - builder.AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1138,23 +1110,22 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::SelfValidation.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - builder.AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context)); + (builder ??= new()).AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context)); - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1172,21 +1143,20 @@ internal sealed partial class __RangeAttributeModelDoubleValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelDouble options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A7); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1204,21 +1174,20 @@ internal sealed partial class __RequiredAttributeModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RequiredAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "RequiredAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RequiredAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1236,36 +1205,35 @@ internal sealed partial class __TypeWithoutOptionsValidatorValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.TypeWithoutOptionsValidator options) { - var baseName = (string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A8); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.YetAnotherComplexVal is not null) { - builder.AddResult(global::TestClasses.OptionsValidation.__RangeAttributeModelDoubleValidator__.Validate(baseName + "YetAnotherComplexVal", options.YetAnotherComplexVal)); + (builder ??= new()).AddResult(global::TestClasses.OptionsValidation.__RangeAttributeModelDoubleValidator__.Validate(string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator.YetAnotherComplexVal" : $"{name}.YetAnotherComplexVal", options.YetAnotherComplexVal)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1282,31 +1250,30 @@ partial class AttributePropertyModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.AttributePropertyModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "AttributePropertyModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "AttributePropertyModel.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A9); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "AttributePropertyModel.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A10); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1323,21 +1290,20 @@ partial class ComplexModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.ComplexModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ComplexModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); if (options.ComplexVal is not null) { - builder.AddResult(global::TestClasses.OptionsValidation.__RequiredAttributeModelValidator__.Validate(baseName + "ComplexVal", options.ComplexVal)); + (builder ??= new()).AddResult(global::TestClasses.OptionsValidation.__RequiredAttributeModelValidator__.Validate(string.IsNullOrEmpty(name) ? "ComplexModel.ComplexVal" : $"{name}.ComplexVal", options.ComplexVal)); } if (options.ValWithoutOptionsValidator is not null) { - builder.AddResult(global::TestClasses.OptionsValidation.__TypeWithoutOptionsValidatorValidator__.Validate(baseName + "ValWithoutOptionsValidator", options.ValWithoutOptionsValidator)); + (builder ??= new()).AddResult(global::TestClasses.OptionsValidation.__TypeWithoutOptionsValidatorValidator__.Validate(string.IsNullOrEmpty(name) ? "ComplexModel.ValWithoutOptionsValidator" : $"{name}.ValWithoutOptionsValidator", options.ValWithoutOptionsValidator)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1354,21 +1320,20 @@ partial class CustomTypeCustomValidationAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.CustomTypeCustomValidationAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "CustomTypeCustomValidationAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "CustomTypeCustomValidationAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A11); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1385,21 +1350,20 @@ partial class CustomValidationAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.CustomValidationAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "CustomValidationAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "CustomValidationAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A12); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1416,21 +1380,20 @@ partial class DataTypeAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.DataTypeAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "DataTypeAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DataTypeAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A13); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1447,41 +1410,40 @@ partial class DerivedModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.DerivedModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "DerivedModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "DerivedVal"; - context.DisplayName = baseName + "DerivedVal"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DerivedModel.DerivedVal" : $"{name}.DerivedVal"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "VirtualValWithAttr"; - context.DisplayName = baseName + "VirtualValWithAttr"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DerivedModel.VirtualValWithAttr" : $"{name}.VirtualValWithAttr"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithAttr!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithAttr, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DerivedModel.Val" : $"{name}.Val"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1498,21 +1460,20 @@ partial class EmailAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.EmailAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "EmailAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "EmailAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A14); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1529,41 +1490,40 @@ partial class LeafModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.LeafModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "LeafModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "VirtualValWithoutAttr"; - context.DisplayName = baseName + "VirtualValWithoutAttr"; + context.DisplayName = string.IsNullOrEmpty(name) ? "LeafModel.VirtualValWithoutAttr" : $"{name}.VirtualValWithoutAttr"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithoutAttr!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithoutAttr, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "DerivedVal"; - context.DisplayName = baseName + "DerivedVal"; + context.DisplayName = string.IsNullOrEmpty(name) ? "LeafModel.DerivedVal" : $"{name}.DerivedVal"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "LeafModel.Val" : $"{name}.Val"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1580,52 +1540,51 @@ partial class MultipleAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.MultipleAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "MultipleAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A15); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A16); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val3"; - context.DisplayName = baseName + "Val3"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val3" : $"{name}.Val3"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A17); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val3!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val3, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val4"; - context.DisplayName = baseName + "Val4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val4" : $"{name}.Val4"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A18); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1642,21 +1601,20 @@ partial class RangeAttributeModelDateValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelDate options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelDate" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelDate.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A19); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1673,21 +1631,20 @@ partial class RangeAttributeModelDoubleValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelDouble options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A7); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1704,21 +1661,20 @@ partial class RangeAttributeModelIntValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelInt options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelInt" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelInt.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A16); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1735,21 +1691,20 @@ partial class RegularExpressionAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RegularExpressionAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "RegularExpressionAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RegularExpressionAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A20); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1766,21 +1721,20 @@ partial class RequiredAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RequiredAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "RequiredAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RequiredAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1798,22 +1752,21 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::ValueTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1830,34 +1783,33 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::ValueTypes.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::ValueTypes.__SecondModelValidator__.Validate(baseName + "P2", options.P2.Value)); + (builder ??= new()).AddResult(global::ValueTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2.Value)); } - builder.AddResult(global::ValueTypes.__SecondModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::ValueTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); if (options.P4 is not null) { - builder.AddResult(global::ValueTypes.__SecondModelValidator__.Validate(baseName + "P4", options.P4.Value)); + (builder ??= new()).AddResult(global::ValueTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P4" : $"{name}.P4", options.P4.Value)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs index 9c68710f2a5ec2..ebdcb1ad6d6ba7 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGenerationTests/Baselines/NetFX/Validators.g.cs @@ -14,22 +14,21 @@ internal sealed partial class __ThirdModelNoNamespaceValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::ThirdModelNoNamespace options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModelNoNamespace" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModelNoNamespace.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } partial class FirstValidatorNoNamespace @@ -43,32 +42,31 @@ partial class FirstValidatorNoNamespace [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::FirstModelNoNamespace options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModelNoNamespace" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModelNoNamespace.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V1.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V1.Validate(string.IsNullOrEmpty(name) ? "FirstModelNoNamespace.P2" : $"{name}.P2", options.P2)); } if (options.P3 is not null) { - builder.AddResult(global::__ThirdModelNoNamespaceValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::__ThirdModelNoNamespaceValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModelNoNamespace.P3" : $"{name}.P3", options.P3)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } partial class SecondValidatorNoNamespace @@ -82,22 +80,21 @@ partial class SecondValidatorNoNamespace [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::SecondModelNoNamespace options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModelNoNamespace" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModelNoNamespace.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } namespace CustomAttr @@ -113,31 +110,30 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::CustomAttr.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A3); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "P2"; - context.DisplayName = baseName + "P2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A4); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -155,22 +151,21 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -188,21 +183,20 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Value"; - context.DisplayName = baseName + "Value"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.Value" : $"{name}.Value"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A5); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Value!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Value, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -219,8 +213,7 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); if (options.P1 is not null) @@ -230,11 +223,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P1[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P1[{count}]" : $"{name}.P1[{count}]", o)); } else { - builder.AddError(baseName + $"P1[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P1[{count}] is null" : $"{name}.P1[{count}] is null"); } count++; } @@ -247,11 +240,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V2.Validate(baseName + $"P2[{count}]", o)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V2.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P2[{count}]" : $"{name}.P2[{count}]", o)); } else { - builder.AddError(baseName + $"P2[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P2[{count}] is null" : $"{name}.P2[{count}] is null"); } count++; } @@ -264,7 +257,7 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P3[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P3[{count}]" : $"{name}.P3[{count}]", o)); } count++; } @@ -275,7 +268,7 @@ partial struct FirstValidator var count = 0; foreach (var o in options.P4) { - builder.AddResult(global::Enumeration.__ThirdModelValidator__.Validate(baseName + $"P4[{count++}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P4[{count++}] is null" : $"{name}.P4[{count++}] is null", o)); } } @@ -286,7 +279,7 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__ThirdModelValidator__.Validate(baseName + $"P5[{count}]", o.Value)); + (builder ??= new()).AddResult(global::Enumeration.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P5[{count}]" : $"{name}.P5[{count}]", o.Value)); } count++; } @@ -299,7 +292,7 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__ThirdModelValidator__.Validate(baseName + $"P51[{count}]", o.Value)); + (builder ??= new()).AddResult(global::Enumeration.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P51[{count}]" : $"{name}.P51[{count}]", o.Value)); } count++; } @@ -312,11 +305,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P6[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P6[{count}]" : $"{name}.P6[{count}]", o)); } else { - builder.AddError(baseName + $"P6[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P6[{count}] is null" : $"{name}.P6[{count}] is null"); } count++; } @@ -328,11 +321,11 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P7[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P7[{count}]" : $"{name}.P7[{count}]", o)); } else { - builder.AddError(baseName + $"P7[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P7[{count}] is null" : $"{name}.P7[{count}] is null"); } count++; } @@ -345,17 +338,17 @@ partial struct FirstValidator { if (o is not null) { - builder.AddResult(global::Enumeration.__SecondModelValidator__.Validate(baseName + $"P8[{count}]", o)); + (builder ??= new()).AddResult(global::Enumeration.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? $"FirstModel.P8[{count}]" : $"{name}.P8[{count}]", o)); } else { - builder.AddError(baseName + $"P8[{count}] is null"); + (builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"FirstModel.P8[{count}] is null" : $"{name}.P8[{count}] is null"); } count++; } } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -372,22 +365,21 @@ partial struct SecondValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Enumeration.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -404,22 +396,21 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::FileScopedNamespace.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -436,21 +427,20 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::FunnyStrings.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A6); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -468,22 +458,21 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Generics.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -500,27 +489,26 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Generics.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P3 is not null) { - builder.AddResult(global::Generics.__SecondModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::Generics.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -537,27 +525,26 @@ partial struct MultiValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::MultiModelValidator.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V3.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V3.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } /// /// Validates a specific named options instance (or all when is ). @@ -568,22 +555,21 @@ partial struct MultiValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::MultiModelValidator.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P3"; - context.DisplayName = baseName + "P3"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P3" : $"{name}.P3"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -601,22 +587,21 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -635,22 +620,21 @@ partial record struct FifthValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -672,34 +656,33 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V4.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V4.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } - builder.AddResult(global::Nested.__ThirdModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::Nested.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); if (options.P4 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V5.Validate(baseName + "P4", options.P4)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V5.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P4" : $"{name}.P4", options.P4)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -720,22 +703,21 @@ partial struct FourthValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -757,22 +739,21 @@ partial struct SecondValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -795,22 +776,21 @@ partial struct ThirdValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Nested.Container1.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -829,22 +809,21 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RandomMembers.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -862,22 +841,21 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P6"; - context.DisplayName = baseName + "P6"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.P6" : $"{name}.P6"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P6, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -894,34 +872,33 @@ partial record struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V6.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V6.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } if (options.P3 is not null) { - builder.AddResult(global::__OptionValidationStaticInstances.__Validators.V7.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::__OptionValidationStaticInstances.__Validators.V7.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); } - builder.AddResult(global::RecordTypes.__ThirdModelValidator__.Validate(baseName + "P4", options.P4)); + (builder ??= new()).AddResult(global::RecordTypes.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P4" : $"{name}.P4", options.P4)); - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -938,22 +915,21 @@ partial record struct SecondValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -970,22 +946,21 @@ partial record class ThirdValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RecordTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1003,26 +978,25 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RepeatedTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P4 is not null) { - builder.AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(baseName + "P4", options.P4)); + (builder ??= new()).AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4", options.P4)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1040,22 +1014,21 @@ internal sealed partial class __ThirdModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RepeatedTypes.ThirdModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ThirdModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P5"; - context.DisplayName = baseName + "P5"; + context.DisplayName = string.IsNullOrEmpty(name) ? "ThirdModel.P5" : $"{name}.P5"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P5, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1072,56 +1045,55 @@ partial class FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::RepeatedTypes.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P1 is not null) { - builder.AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(baseName + "P1", options.P1)); + (builder ??= new()).AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1", options.P1)); } context.MemberName = "P2"; - context.DisplayName = baseName + "P2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(baseName + "P2", options.P2)); + (builder ??= new()).AddResult(global::RepeatedTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2)); } context.MemberName = "P3"; - context.DisplayName = baseName + "P3"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P3, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P3 is not null) { - builder.AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::RepeatedTypes.__ThirdModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1138,23 +1110,22 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::SelfValidation.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - builder.AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context)); + (builder ??= new()).AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context)); - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1172,21 +1143,20 @@ internal sealed partial class __RangeAttributeModelDoubleValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelDouble options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A7); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1204,21 +1174,20 @@ internal sealed partial class __RequiredAttributeModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RequiredAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "RequiredAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RequiredAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1236,36 +1205,35 @@ internal sealed partial class __TypeWithoutOptionsValidatorValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.TypeWithoutOptionsValidator options) { - var baseName = (string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A8); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.YetAnotherComplexVal is not null) { - builder.AddResult(global::TestClasses.OptionsValidation.__RangeAttributeModelDoubleValidator__.Validate(baseName + "YetAnotherComplexVal", options.YetAnotherComplexVal)); + (builder ??= new()).AddResult(global::TestClasses.OptionsValidation.__RangeAttributeModelDoubleValidator__.Validate(string.IsNullOrEmpty(name) ? "TypeWithoutOptionsValidator.YetAnotherComplexVal" : $"{name}.YetAnotherComplexVal", options.YetAnotherComplexVal)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1282,31 +1250,30 @@ partial class AttributePropertyModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.AttributePropertyModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "AttributePropertyModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "AttributePropertyModel.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A9); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "AttributePropertyModel.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A10); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1323,21 +1290,20 @@ partial class ComplexModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.ComplexModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "ComplexModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); if (options.ComplexVal is not null) { - builder.AddResult(global::TestClasses.OptionsValidation.__RequiredAttributeModelValidator__.Validate(baseName + "ComplexVal", options.ComplexVal)); + (builder ??= new()).AddResult(global::TestClasses.OptionsValidation.__RequiredAttributeModelValidator__.Validate(string.IsNullOrEmpty(name) ? "ComplexModel.ComplexVal" : $"{name}.ComplexVal", options.ComplexVal)); } if (options.ValWithoutOptionsValidator is not null) { - builder.AddResult(global::TestClasses.OptionsValidation.__TypeWithoutOptionsValidatorValidator__.Validate(baseName + "ValWithoutOptionsValidator", options.ValWithoutOptionsValidator)); + (builder ??= new()).AddResult(global::TestClasses.OptionsValidation.__TypeWithoutOptionsValidatorValidator__.Validate(string.IsNullOrEmpty(name) ? "ComplexModel.ValWithoutOptionsValidator" : $"{name}.ValWithoutOptionsValidator", options.ValWithoutOptionsValidator)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1354,21 +1320,20 @@ partial class CustomTypeCustomValidationAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.CustomTypeCustomValidationAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "CustomTypeCustomValidationAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "CustomTypeCustomValidationAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A11); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1385,21 +1350,20 @@ partial class CustomValidationAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.CustomValidationAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "CustomValidationAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "CustomValidationAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A12); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1416,21 +1380,20 @@ partial class DataTypeAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.DataTypeAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "DataTypeAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DataTypeAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A13); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1447,41 +1410,40 @@ partial class DerivedModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.DerivedModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "DerivedModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "DerivedVal"; - context.DisplayName = baseName + "DerivedVal"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DerivedModel.DerivedVal" : $"{name}.DerivedVal"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "VirtualValWithAttr"; - context.DisplayName = baseName + "VirtualValWithAttr"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DerivedModel.VirtualValWithAttr" : $"{name}.VirtualValWithAttr"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithAttr!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithAttr, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "DerivedModel.Val" : $"{name}.Val"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1498,21 +1460,20 @@ partial class EmailAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.EmailAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "EmailAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "EmailAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A14); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1529,41 +1490,40 @@ partial class LeafModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.LeafModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "LeafModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "VirtualValWithoutAttr"; - context.DisplayName = baseName + "VirtualValWithoutAttr"; + context.DisplayName = string.IsNullOrEmpty(name) ? "LeafModel.VirtualValWithoutAttr" : $"{name}.VirtualValWithoutAttr"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithoutAttr!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.VirtualValWithoutAttr, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "DerivedVal"; - context.DisplayName = baseName + "DerivedVal"; + context.DisplayName = string.IsNullOrEmpty(name) ? "LeafModel.DerivedVal" : $"{name}.DerivedVal"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.DerivedVal, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "LeafModel.Val" : $"{name}.Val"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1580,52 +1540,51 @@ partial class MultipleAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.MultipleAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "MultipleAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "Val1"; - context.DisplayName = baseName + "Val1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val1" : $"{name}.Val1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A15); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val2"; - context.DisplayName = baseName + "Val2"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val2" : $"{name}.Val2"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A16); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val2, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val3"; - context.DisplayName = baseName + "Val3"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val3" : $"{name}.Val3"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A17); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val3!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val3, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } context.MemberName = "Val4"; - context.DisplayName = baseName + "Val4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "MultipleAttributeModel.Val4" : $"{name}.Val4"; validationResults.Clear(); validationAttributes.Clear(); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A18); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1642,21 +1601,20 @@ partial class RangeAttributeModelDateValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelDate options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelDate" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelDate.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A8); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1673,21 +1631,20 @@ partial class RangeAttributeModelDoubleValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelDouble options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelDouble.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A7); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1704,21 +1661,20 @@ partial class RangeAttributeModelIntValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RangeAttributeModelInt options) { - var baseName = (string.IsNullOrEmpty(name) ? "RangeAttributeModelInt" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RangeAttributeModelInt.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A16); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1735,21 +1691,20 @@ partial class RegularExpressionAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RegularExpressionAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "RegularExpressionAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RegularExpressionAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A19); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1766,21 +1721,20 @@ partial class RequiredAttributeModelValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::TestClasses.OptionsValidation.RequiredAttributeModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "RequiredAttributeModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(1); context.MemberName = "Val"; - context.DisplayName = baseName + "Val"; + context.DisplayName = string.IsNullOrEmpty(name) ? "RequiredAttributeModel.Val" : $"{name}.Val"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1798,22 +1752,21 @@ internal sealed partial class __SecondModelValidator__ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::ValueTypes.SecondModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "SecondModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P4"; - context.DisplayName = baseName + "P4"; + context.DisplayName = string.IsNullOrEmpty(name) ? "SecondModel.P4" : $"{name}.P4"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P4, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } @@ -1830,34 +1783,33 @@ partial struct FirstValidator [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::ValueTypes.FirstModel options) { - var baseName = (string.IsNullOrEmpty(name) ? "FirstModel" : name) + "."; - var builder = new global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder(); + global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); var validationResults = new global::System.Collections.Generic.List(); var validationAttributes = new global::System.Collections.Generic.List(2); context.MemberName = "P1"; - context.DisplayName = baseName + "P1"; + context.DisplayName = string.IsNullOrEmpty(name) ? "FirstModel.P1" : $"{name}.P1"; validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); - if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1!, context, validationResults, validationAttributes)) + if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes)) { - builder.AddResults(validationResults); + (builder ??= new()).AddResults(validationResults); } if (options.P2 is not null) { - builder.AddResult(global::ValueTypes.__SecondModelValidator__.Validate(baseName + "P2", options.P2.Value)); + (builder ??= new()).AddResult(global::ValueTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P2" : $"{name}.P2", options.P2.Value)); } - builder.AddResult(global::ValueTypes.__SecondModelValidator__.Validate(baseName + "P3", options.P3)); + (builder ??= new()).AddResult(global::ValueTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P3" : $"{name}.P3", options.P3)); if (options.P4 is not null) { - builder.AddResult(global::ValueTypes.__SecondModelValidator__.Validate(baseName + "P4", options.P4.Value)); + (builder ??= new()).AddResult(global::ValueTypes.__SecondModelValidator__.Validate(string.IsNullOrEmpty(name) ? "FirstModel.P4" : $"{name}.P4", options.P4.Value)); } - return builder.Build(); + return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); } } } From dc652c10e9ea4c6c9fffab50647b0b2350377dba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:31:41 -0600 Subject: [PATCH 125/345] [release/8.0] [nodejs] Remove experimental wasm arguments from template (#91401) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove experimental wasm arguments from template and add them to features.md * Fix WBT * Use lowercase host in runtimeconfig.template.json * Override runtimeconfig only for wasmconsole --------- Co-authored-by: Marek Fišera Co-authored-by: Marek Safar --- .../Wasm.Build.Tests/WasmTemplateTestBase.cs | 36 +++++++++++++++---- src/mono/wasm/features.md | 18 ++++++++++ .../console/runtimeconfig.template.json | 8 ++--- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs index 6280a022c1a424..a7ae3fba70ed30 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTestBase.cs @@ -3,7 +3,9 @@ #nullable enable +using System; using System.IO; +using System.Text.Json.Nodes; using Xunit.Abstractions; namespace Wasm.Build.Tests; @@ -45,18 +47,38 @@ public string CreateWasmTemplateProject(string id, string template = "wasmbrowse if (runAnalyzers) extraProperties += "true"; - // TODO: Can be removed after updated templates propagate in. - string extraItems = string.Empty; - if (template == "wasmbrowser") - extraItems += ""; - else - extraItems += ""; + if (template == "wasmconsole") + { + UpdateRuntimeconfigTemplateForNode(_projectDir); + } - AddItemsPropertiesToProject(projectfile, extraProperties, extraItems); + AddItemsPropertiesToProject(projectfile, extraProperties); return projectfile; } + private static void UpdateRuntimeconfigTemplateForNode(string projectDir) + { + // TODO: Can be removed once Node >= 20 + + string runtimeconfigTemplatePath = Path.Combine(projectDir, "runtimeconfig.template.json"); + string runtimeconfigTemplateContent = File.ReadAllText(runtimeconfigTemplatePath); + var runtimeconfigTemplate = JsonObject.Parse(runtimeconfigTemplateContent); + if (runtimeconfigTemplate == null) + throw new Exception($"Unable to parse runtimeconfigtemplate at '{runtimeconfigTemplatePath}'"); + + var perHostConfigs = runtimeconfigTemplate?["wasmHostProperties"]?["perHostConfig"]?.AsArray(); + if (perHostConfigs == null || perHostConfigs.Count == 0 || perHostConfigs[0] == null) + throw new Exception($"Unable to find perHostConfig in runtimeconfigtemplate at '{runtimeconfigTemplatePath}'"); + + perHostConfigs[0]!["host-args"] = new JsonArray( + "--experimental-wasm-simd", + "--experimental-wasm-eh" + ); + + File.WriteAllText(runtimeconfigTemplatePath, runtimeconfigTemplate!.ToString()); + } + public (string projectDir, string buildOutput) BuildTemplateProject(BuildArgs buildArgs, string id, BuildProjectOptions buildProjectOptions) diff --git a/src/mono/wasm/features.md b/src/mono/wasm/features.md index c131002dde7968..d3d85f2e570a9e 100644 --- a/src/mono/wasm/features.md +++ b/src/mono/wasm/features.md @@ -292,6 +292,24 @@ A WebAssembly application that works well on desktop PCs browser may take minute ### Shell environments - NodeJS & V8 While our primary target is web browsers, we have partial support for Node.JS v14 sufficient to pass most of our automated tests. We also have partial support for the D8 command-line shell, version 11 or higher, sufficient to pass most of our automated tests. Both of these environments may lack support for features that are available in the browser. +#### NodeJS < 20 +Until node version 20, you may need to pass these arguments when running the application `--experimental-wasm-simd --experimental-wasm-eh`. When you run the application using `dotnet run`, you can add these to the runtimeconfig template + +```json +"wasmHostProperties": { + "perHostConfig": [ + { + "name": "node", + ... + "host-args": [ + "--experimental-wasm-simd", // 👈 Enable SIMD support + "--experimental-wasm-eh" // 👈 Enable exception handling support + ] + } + ] +} +``` + ## Choosing the right platform target Every end user has different needs, so the right platform for every application may differ. diff --git a/src/mono/wasm/templates/templates/console/runtimeconfig.template.json b/src/mono/wasm/templates/templates/console/runtimeconfig.template.json index 49721faa0baa4d..a056e67f11cf9a 100644 --- a/src/mono/wasm/templates/templates/console/runtimeconfig.template.json +++ b/src/mono/wasm/templates/templates/console/runtimeconfig.template.json @@ -4,12 +4,8 @@ { "name": "node", "js-path": "main.mjs", - "Host": "nodejs", - "host-args": [ - "--experimental-wasm-simd", - "--experimental-wasm-eh" - ] + "host": "nodejs" } ] } -} +} \ No newline at end of file From 4d6f6bc30fcd1423992023865e50044a32f018d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:33:48 -0600 Subject: [PATCH 126/345] Fix arm64/arm32 cross-DAC (#91438) The precode code was incorrectly using the HOST_ARM64, HOST_ARM, etc. defines instead of the TARGET_ ones. This means the cross-DAC was using the wrong architectures *Precode::Type codes. Co-authored-by: Mike McLaughlin --- src/coreclr/vm/precode.h | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index d7f6b4cac1a74d..158c1ab08f5545 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -11,7 +11,7 @@ #define PRECODE_ALIGNMENT sizeof(void*) -#if defined(HOST_AMD64) +#if defined(TARGET_AMD64) #define OFFSETOF_PRECODE_TYPE 0 #define OFFSETOF_PRECODE_TYPE_CALL_OR_JMP 5 @@ -19,7 +19,7 @@ #define SIZEOF_PRECODE_BASE 16 -#elif defined(HOST_X86) +#elif defined(TARGET_X86) EXTERN_C VOID STDCALL PrecodeRemotingThunk(); @@ -29,27 +29,27 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk(); #define SIZEOF_PRECODE_BASE 8 -#elif defined(HOST_ARM64) +#elif defined(TARGET_ARM64) #define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN #define OFFSETOF_PRECODE_TYPE 0 -#elif defined(HOST_ARM) +#elif defined(TARGET_ARM) #define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN #define OFFSETOF_PRECODE_TYPE 3 -#elif defined(HOST_LOONGARCH64) +#elif defined(TARGET_LOONGARCH64) #define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN #define OFFSETOF_PRECODE_TYPE 0 -#elif defined(HOST_RISCV64) +#elif defined(TARGET_RISCV64) #define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN #define OFFSETOF_PRECODE_TYPE 0 -#endif // HOST_AMD64 +#endif // TARGET_AMD64 #ifndef DACCESS_COMPILE // Given an address in a slot, figure out if the prestub will be called @@ -61,14 +61,14 @@ BOOL DoesSlotCallPrestub(PCODE pCode); // Invalid precode type struct InvalidPrecode { -#if defined(HOST_AMD64) || defined(HOST_X86) +#if defined(TARGET_AMD64) || defined(TARGET_X86) // int3 static const int Type = 0xCC; -#elif defined(HOST_ARM64) || defined(HOST_ARM) +#elif defined(TARGET_ARM64) || defined(TARGET_ARM) static const int Type = 0; -#elif defined(HOST_LOONGARCH64) +#elif defined(TARGET_LOONGARCH64) static const int Type = 0xff; -#elif defined(HOST_RISCV64) +#elif defined(TARGET_RISCV64) static const int Type = 0xff; #endif }; @@ -90,25 +90,25 @@ extern "C" void StubPrecodeCode_End(); // Regular precode struct StubPrecode { -#if defined(HOST_AMD64) +#if defined(TARGET_AMD64) static const BYTE Type = 0x4C; static const SIZE_T CodeSize = 24; -#elif defined(HOST_X86) +#elif defined(TARGET_X86) static const BYTE Type = 0xA1; static const SIZE_T CodeSize = 24; -#elif defined(HOST_ARM64) +#elif defined(TARGET_ARM64) static const int Type = 0x4A; static const SIZE_T CodeSize = 24; -#elif defined(HOST_ARM) +#elif defined(TARGET_ARM) static const int Type = 0xCF; static const SIZE_T CodeSize = 12; -#elif defined(HOST_LOONGARCH64) +#elif defined(TARGET_LOONGARCH64) static const int Type = 0x4; static const SIZE_T CodeSize = 24; -#elif defined(HOST_RISCV64) +#elif defined(TARGET_RISCV64) static const int Type = 0x17; static const SIZE_T CodeSize = 24; -#endif // HOST_AMD64 +#endif // TARGET_AMD64 BYTE m_code[CodeSize]; @@ -224,31 +224,31 @@ extern "C" void FixupPrecodeCode_End(); // The fixup precode is simple jump once patched. It does not have the two instruction overhead of regular precode. struct FixupPrecode { -#if defined(HOST_AMD64) +#if defined(TARGET_AMD64) static const int Type = 0xFF; static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 6; -#elif defined(HOST_X86) +#elif defined(TARGET_X86) static const int Type = 0xFF; static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 6; -#elif defined(HOST_ARM64) +#elif defined(TARGET_ARM64) static const int Type = 0x0B; static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 8; -#elif defined(HOST_ARM) +#elif defined(TARGET_ARM) static const int Type = 0xFF; static const SIZE_T CodeSize = 12; static const int FixupCodeOffset = 4 + THUMB_CODE; -#elif defined(HOST_LOONGARCH64) +#elif defined(TARGET_LOONGARCH64) static const int Type = 0x3; static const SIZE_T CodeSize = 32; static const int FixupCodeOffset = 12; -#elif defined(HOST_RISCV64) +#elif defined(TARGET_RISCV64) static const int Type = 0x97; static const SIZE_T CodeSize = 32; static const int FixupCodeOffset = 10; -#endif // HOST_AMD64 +#endif // TARGET_AMD64 BYTE m_code[CodeSize]; From 2134e6210b5eb944c834744877d8d06401b1c845 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:34:35 -0600 Subject: [PATCH 127/345] Fix runtime dispatch to static virtuals on interface types (#91440) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were not generating information about static virtuals on interface types. Information about default interface methods normally goes to the class, but if the T we're dispatching on is an interface, this information wasn't generated. The fix is to put this information into dispatch maps and sealed vtables, same way we do for classes. The test shows what the problem is - if we change `IBar` to be a class, things would work even before this PR. Co-authored-by: Michal Strehovský --- .../Common/MetadataVirtualMethodAlgorithm.cs | 9 ++- .../Compiler/DependencyAnalysis/EETypeNode.cs | 19 ++--- .../InterfaceDispatchMapNode.cs | 34 +++++++-- .../DependencyAnalysis/SealedVTableNode.cs | 14 +++- .../Compiler/VirtualMethodCallHelper.cs | 5 +- .../SmokeTests/UnitTests/Interfaces.cs | 73 +++++++++++++++++++ 6 files changed, 132 insertions(+), 22 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs index 8d2b8a4e3fd3fe..330296b18dbfa4 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataVirtualMethodAlgorithm.cs @@ -614,6 +614,8 @@ private static MethodDesc ResolveInterfaceMethodToVirtualMethodOnType(MethodDesc { Debug.Assert(!interfaceMethod.Signature.IsStatic); + // This would be a default interface method resolution. The algorithm below would sort of work, but doesn't handle + // things like diamond cases and it's better not to let it resolve as such. if (currentType.IsInterface) return null; @@ -781,7 +783,7 @@ private static DefaultInterfaceMethodResolution ResolveInterfaceMethodToDefaultI // If we're asking about an interface, include the interface in the list. consideredInterfaces = new DefType[currentType.RuntimeInterfaces.Length + 1]; Array.Copy(currentType.RuntimeInterfaces, consideredInterfaces, currentType.RuntimeInterfaces.Length); - consideredInterfaces[consideredInterfaces.Length - 1] = (DefType)currentType.InstantiateAsOpen(); + consideredInterfaces[consideredInterfaces.Length - 1] = currentType.IsGenericDefinition ? (DefType)currentType.InstantiateAsOpen() : currentType; } foreach (MetadataType runtimeInterface in consideredInterfaces) @@ -921,6 +923,11 @@ public static IEnumerable EnumAllVirtualSlots(MetadataType type) /// MethodDesc of the resolved virtual static method, null when not found (runtime lookup must be used) public static MethodDesc ResolveInterfaceMethodToStaticVirtualMethodOnType(MethodDesc interfaceMethod, MetadataType currentType) { + // This would be a default interface method resolution. The algorithm below would sort of work, but doesn't handle + // things like diamond cases and it's better not to let it resolve as such. + if (currentType.IsInterface) + return null; + // Search for match on a per-level in the type hierarchy for (MetadataType typeToCheck = currentType; typeToCheck != null; typeToCheck = typeToCheck.MetadataBaseType) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index 1e9f7679b44cc3..61520b4bfadaff 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -372,16 +372,8 @@ public sealed override IEnumerable GetConditionalSt DefType defType = _type.GetClosestDefType(); - // Interfaces don't have vtables and we don't need to track their slot use. - // The only exception are those interfaces that provide IDynamicInterfaceCastable implementations; - // those have slots and we dispatch on them. - bool needsDependenciesForVirtualMethodImpls = !defType.IsInterface - || ((MetadataType)defType).IsDynamicInterfaceCastableImplementation(); - // If we're producing a full vtable, none of the dependencies are conditional. - needsDependenciesForVirtualMethodImpls &= !factory.VTable(defType).HasFixedSlots; - - if (needsDependenciesForVirtualMethodImpls) + if (!factory.VTable(defType).HasFixedSlots) { bool isNonInterfaceAbstractType = !defType.IsInterface && ((MetadataType)defType).IsAbstract; @@ -436,6 +428,12 @@ public sealed override IEnumerable GetConditionalSt ((System.Collections.IStructuralEquatable)defType.RuntimeInterfaces).Equals(_type.RuntimeInterfaces, EqualityComparer.Default)); + // Interfaces don't have vtables and we don't need to track their instance method slot use. + // The only exception are those interfaces that provide IDynamicInterfaceCastable implementations; + // those have slots and we dispatch on them. + bool needsDependenciesForInstanceInterfaceMethodImpls = !defType.IsInterface + || ((MetadataType)defType).IsDynamicInterfaceCastableImplementation(); + // Add conditional dependencies for interface methods the type implements. For example, if the type T implements // interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's // possible for any IFoo object to actually be an instance of T. @@ -456,6 +454,9 @@ public sealed override IEnumerable GetConditionalSt bool isStaticInterfaceMethod = interfaceMethod.Signature.IsStatic; + if (!isStaticInterfaceMethod && !needsDependenciesForInstanceInterfaceMethodImpls) + continue; + MethodDesc implMethod = isStaticInterfaceMethod ? defType.ResolveInterfaceMethodToStaticVirtualMethodOnType(interfaceMethod) : defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs index 38104d7ab015c9..c2ac4568c748c9 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs @@ -73,7 +73,7 @@ public static bool MightHaveInterfaceDispatchMap(TypeDesc type, NodeFactory fact if (!type.IsArray && !type.IsDefType) return false; - // Interfaces don't have a dispatch map because we dispatch them based on the + // Interfaces don't have a dispatch map for instance methods because we dispatch them based on the // dispatch map of the implementing class. // The only exception are IDynamicInterfaceCastable scenarios that dispatch // using the interface dispatch map. @@ -83,8 +83,9 @@ public static bool MightHaveInterfaceDispatchMap(TypeDesc type, NodeFactory fact // wasn't marked as [DynamicInterfaceCastableImplementation]" and "we couldn't find an // implementation". We don't want to use the custom attribute for that at runtime because // that's reflection and this should work without reflection. - if (type.IsInterface) - return ((MetadataType)type).IsDynamicInterfaceCastableImplementation(); + bool isInterface = type.IsInterface; + if (isInterface && ((MetadataType)type).IsDynamicInterfaceCastableImplementation()) + return true; DefType declType = type.GetClosestDefType(); @@ -112,6 +113,11 @@ public static bool MightHaveInterfaceDispatchMap(TypeDesc type, NodeFactory fact Debug.Assert(declMethod.IsVirtual); + // Only static methods get placed in dispatch maps of interface types (modulo + // IDynamicInterfaceCastable we already handled above). + if (isInterface && !declMethod.Signature.IsStatic) + continue; + if (interfaceOnDefinitionType != null) declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), interfaceOnDefinitionType); @@ -154,6 +160,10 @@ private void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) var staticImplementations = new List<(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>(); var staticDefaultImplementations = new List<(int InterfaceIndex, int InterfaceMethodSlot, int ImplMethodSlot, int Context)>(); + bool isInterface = declType.IsInterface; + bool needsEntriesForInstanceInterfaceMethodImpls = !isInterface + || ((MetadataType)declType).IsDynamicInterfaceCastableImplementation(); + // Resolve all the interfaces, but only emit non-static and non-default implementations for (int interfaceIndex = 0; interfaceIndex < declTypeRuntimeInterfaces.Length; interfaceIndex++) { @@ -166,6 +176,10 @@ private void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; + + if (!declMethod.Signature.IsStatic && !needsEntriesForInstanceInterfaceMethodImpls) + continue; + if(!interfaceType.IsTypeDefinition) declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType); @@ -244,9 +258,17 @@ private void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) // For default interface methods, the generic context is acquired by indexing // into the interface list of the owning type. Debug.Assert(providingInterfaceDefinitionType != null); - int indexOfInterface = Array.IndexOf(declTypeDefinitionRuntimeInterfaces, providingInterfaceDefinitionType); - Debug.Assert(indexOfInterface >= 0); - genericContext = StaticVirtualMethodContextSource.ContextFromFirstInterface + indexOfInterface; + if (declTypeDefinition.HasSameTypeDefinition(providingInterfaceDefinitionType) && + providingInterfaceDefinitionType == declTypeDefinition.InstantiateAsOpen()) + { + genericContext = StaticVirtualMethodContextSource.ContextFromThisClass; + } + else + { + int indexOfInterface = Array.IndexOf(declTypeDefinitionRuntimeInterfaces, providingInterfaceDefinitionType); + Debug.Assert(indexOfInterface >= 0); + genericContext = StaticVirtualMethodContextSource.ContextFromFirstInterface + indexOfInterface; + } } staticDefaultImplementations.Add(( interfaceIndex, diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs index bb67f884264dd3..a8460e80d0b413 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SealedVTableNode.cs @@ -108,17 +108,21 @@ public bool BuildSealedVTableSlots(NodeFactory factory, bool relocsOnly) _sealedVTableEntries = new List(); - // Interfaces don't have any virtual slots with the exception of interfaces that provide + // Interfaces don't have any instance virtual slots with the exception of interfaces that provide // IDynamicInterfaceCastable implementation. // Normal interface don't need one because the dispatch is done at the class level. // For IDynamicInterfaceCastable, we don't have an implementing class. - if (_type.IsInterface && !((MetadataType)_type).IsDynamicInterfaceCastableImplementation()) - return true; + bool isInterface = declType.IsInterface; + bool needsEntriesForInstanceInterfaceMethodImpls = !isInterface + || ((MetadataType)declType).IsDynamicInterfaceCastableImplementation(); IReadOnlyList virtualSlots = factory.VTable(declType).Slots; for (int i = 0; i < virtualSlots.Count; i++) { + if (!virtualSlots[i].Signature.IsStatic && !needsEntriesForInstanceInterfaceMethodImpls) + continue; + MethodDesc implMethod = declType.FindVirtualFunctionTargetMethodOnObjectType(virtualSlots[i]); if (implMethod.CanMethodBeInSealedVTable()) @@ -143,6 +147,10 @@ public bool BuildSealedVTableSlots(NodeFactory factory, bool relocsOnly) for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++) { MethodDesc declMethod = virtualSlots[interfaceMethodSlot]; + + if (!declMethod.Signature.IsStatic && !needsEntriesForInstanceInterfaceMethodImpls) + continue; + if (!interfaceType.IsTypeDefinition) declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/VirtualMethodCallHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/VirtualMethodCallHelper.cs index a9de1fce5e3a52..ec398d37433966 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/VirtualMethodCallHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/VirtualMethodCallHelper.cs @@ -93,9 +93,8 @@ private static int GetNumberOfSlotsInCurrentType(NodeFactory factory, TypeDesc i { if (implType.IsInterface) { - // We normally don't need to ask about vtable slots of interfaces. It's not wrong to ask - // that question, but we currently only ask it for IDynamicInterfaceCastable implementations. - Debug.Assert(((MetadataType)implType).IsDynamicInterfaceCastableImplementation()); + // Interface types don't have physically assigned virtual slots, so the number of slots + // is always 0. They may have sealed slots. return (implType.HasGenericDictionarySlot() && countDictionarySlots) ? 1 : 0; } diff --git a/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs b/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs index f163dbba5ba6c7..7ad4f974bbb09c 100644 --- a/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs +++ b/src/tests/nativeaot/SmokeTests/UnitTests/Interfaces.cs @@ -52,6 +52,8 @@ public static int Run() TestMoreConstraints.Run(); TestSimpleNonGeneric.Run(); TestSimpleGeneric.Run(); + TestDefaultDynamicStaticNonGeneric.Run(); + TestDefaultDynamicStaticGeneric.Run(); TestDynamicStaticGenericVirtualMethods.Run(); return Pass; @@ -1502,6 +1504,77 @@ public static void Run() } } + class TestDefaultDynamicStaticNonGeneric + { + interface IFoo + { + abstract static string ImHungryGiveMeCookie(); + } + + interface IBar : IFoo + { + static string IFoo.ImHungryGiveMeCookie() => "IBar"; + } + + class Baz : IBar + { + } + + class Gen where T : IFoo + { + public static string GrabCookie() => T.ImHungryGiveMeCookie(); + } + + public static void Run() + { + var r = (string)typeof(Gen<>).MakeGenericType(typeof(Baz)).GetMethod("GrabCookie").Invoke(null, Array.Empty()); + if (r != "IBar") + throw new Exception(r); + + r = (string)typeof(Gen<>).MakeGenericType(typeof(IBar)).GetMethod("GrabCookie").Invoke(null, Array.Empty()); + if (r != "IBar") + throw new Exception(r); + } + } + + class TestDefaultDynamicStaticGeneric + { + class Atom1 { } + class Atom2 { } + + interface IFoo + { + abstract static string ImHungryGiveMeCookie(); + } + + interface IBar : IFoo + { + static string IFoo.ImHungryGiveMeCookie() => $"IBar<{typeof(T).Name}>"; + } + + class Baz : IBar + { + } + + class Gen where T : IFoo + { + public static string GrabCookie() => T.ImHungryGiveMeCookie(); + } + + public static void Run() + { + Activator.CreateInstance(typeof(Baz<>).MakeGenericType(typeof(Atom1))); + + var r = (string)typeof(Gen<>).MakeGenericType(typeof(Baz<>).MakeGenericType(typeof(Atom1))).GetMethod("GrabCookie").Invoke(null, Array.Empty()); + if (r != "IBar") + throw new Exception(r); + + r = (string)typeof(Gen<>).MakeGenericType(typeof(IBar<>).MakeGenericType(typeof(Atom2))).GetMethod("GrabCookie").Invoke(null, Array.Empty()); + if (r != "IBar") + throw new Exception(r); + } + } + class TestDynamicStaticGenericVirtualMethods { interface IEntry From 62b57fcc780640032a3c385015633419a736508f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:38:59 -0600 Subject: [PATCH 128/345] Fix LDTOKEN of methods that have modifiers (#91439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we started generating custom modifiers into metadata format to support new function pointer APIs in #85504, we should have also added it to native layout format. We currently have a mismatch. This is a low risk bugfix to ignore modifiers on the metadata side. We'll want to do a full fix to actually emit and compare this. Tracked in a .NET 9 bug at #91381. No regression test because I spent too much time being puzzled at why https://github.com/Handlebars-Net/Handlebars.Net/blob/50614fd844e5360eb10e76154aa74da4d7bf12ce/source/Handlebars/Helpers/IHelperDescriptor.cs#L13 is generated as a custom modifier (`[in] !TOptions& modreq([netstandard]System.Runtime.InteropServices.InAttribute) options`) whereas if I do it, I get `[in] !T& 'value'` with a custom attribute. We'll want to write a proper set of tests with ambiguities for the bug I opened anyway. Co-authored-by: Michal Strehovský --- ...derEnvironment.MetadataSignatureParsing.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.MetadataSignatureParsing.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.MetadataSignatureParsing.cs index 07674dded3541c..1a1cd76cc4ddfd 100644 --- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.MetadataSignatureParsing.cs +++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.MetadataSignatureParsing.cs @@ -173,12 +173,23 @@ internal static NativeParser GetNativeParserForSignature(RuntimeSignature signat private bool CompareTypeSigWithType(ref NativeParser parser, TypeManagerHandle moduleHandle, Handle typeHandle) { - while (typeHandle.HandleType == HandleType.TypeSpecification) + while (typeHandle.HandleType == HandleType.TypeSpecification + || typeHandle.HandleType == HandleType.ModifiedType) { - typeHandle = typeHandle - .ToTypeSpecificationHandle(_metadataReader) - .GetTypeSpecification(_metadataReader) - .Signature; + if (typeHandle.HandleType == HandleType.TypeSpecification) + { + typeHandle = typeHandle + .ToTypeSpecificationHandle(_metadataReader) + .GetTypeSpecification(_metadataReader) + .Signature; + } + else + { + typeHandle = typeHandle + .ToModifiedTypeHandle(_metadataReader) + .GetModifiedType(_metadataReader) + .Type; + } } // startOffset lets us backtrack to the TypeSignatureKind for external types since the TypeLoader From ed4863553c6c16087fab627c1020dc5531118dfb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:15:06 -0600 Subject: [PATCH 129/345] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230831.4 (#91462) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23430.6 -> To Version 1.0.0-prerelease.23431.4 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fe4d19e4449095..32f9f3c8c6fc41 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 804d586c07a6c598551a2913f0958680cb9135a9 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 3fbd3234f952f4c410e35701d0b66272d27cfb6c + 07f1da26c7bd97db0defad5e38bed5e514eb960e - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 3fbd3234f952f4c410e35701d0b66272d27cfb6c + 07f1da26c7bd97db0defad5e38bed5e514eb960e - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 3fbd3234f952f4c410e35701d0b66272d27cfb6c + 07f1da26c7bd97db0defad5e38bed5e514eb960e - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 3fbd3234f952f4c410e35701d0b66272d27cfb6c + 07f1da26c7bd97db0defad5e38bed5e514eb960e https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 3fbd3234f952f4c410e35701d0b66272d27cfb6c + 07f1da26c7bd97db0defad5e38bed5e514eb960e - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 3fbd3234f952f4c410e35701d0b66272d27cfb6c + 07f1da26c7bd97db0defad5e38bed5e514eb960e diff --git a/eng/Versions.props b/eng/Versions.props index 93153b418cab7c..5b7fc280e32618 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23430.6 - 1.0.0-prerelease.23430.6 - 1.0.0-prerelease.23430.6 - 1.0.0-prerelease.23430.6 - 1.0.0-prerelease.23430.6 - 1.0.0-prerelease.23430.6 + 1.0.0-prerelease.23431.4 + 1.0.0-prerelease.23431.4 + 1.0.0-prerelease.23431.4 + 1.0.0-prerelease.23431.4 + 1.0.0-prerelease.23431.4 + 1.0.0-prerelease.23431.4 16.11.27-beta1.23180.1 2.0.0-beta4.23307.1 From 7c8fc57534e27c4cb52663e097208e3ed0cdc21e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:25:51 -0600 Subject: [PATCH 130/345] [release/8.0] Update dependencies from dotnet/emsdk dotnet/arcade (#91423) * Update dependencies from https://github.com/dotnet/emsdk build 20230831.1 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.1.23415.5 -> To Version 8.0.0-rc.2.23431.1 Dependency coherency updates runtime.linux-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.win-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.win-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.osx-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.osx-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.win-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.win-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.osx-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.osx-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.osx-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.osx-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.osx-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.osx-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools From Version 16.0.5-alpha.1.23408.1 -> To Version 16.0.5-alpha.1.23423.1 (parent: Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport * Update dependencies from https://github.com/dotnet/arcade build 20230831.2 Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.TargetFramework , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.GenAPI , Microsoft.DotNet.GenFacades , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.SharedFramework.Sdk , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.XUnitExtensions From Version 8.0.0-beta.23429.1 -> To Version 8.0.0-beta.23431.2 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 196 +++++++++++++++---------------- eng/Versions.props | 92 +++++++-------- eng/common/cross/toolchain.cmake | 2 +- global.json | 6 +- 4 files changed, 148 insertions(+), 148 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 32f9f3c8c6fc41..5c942861fff1de 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,69 +12,69 @@ https://github.com/dotnet/wcf 7f504aabb1988e9a093c1e74d8040bd52feb2f01 - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d https://github.com/dotnet/command-line-api @@ -90,9 +90,9 @@ fa5acbd2ccba88c9d46ce0dd8f5310f9d3c5c46d - + https://github.com/dotnet/emsdk - 66dbaefff04250dc72849f0172e0c53bcfb3ab38 + 300725997600f884161d74f9889251ba842e44f5 @@ -107,9 +107,9 @@ - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 @@ -117,69 +117,69 @@ 194f32828726c3f1f63f79f3dc09b9e99c157b11 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 https://github.com/dotnet/runtime-assets @@ -233,61 +233,61 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d - + https://github.com/dotnet/llvm-project - 9b77c16a6061fb1160ec12bd307badb4c58dff98 + 08a449c9a9bf593b29fc05de2f424e6882320e5d https://github.com/dotnet/runtime @@ -330,9 +330,9 @@ https://github.com/dotnet/xharness 480b9159eb7e69b182a87581d5a336e97e0b6dae - + https://github.com/dotnet/arcade - 804d586c07a6c598551a2913f0958680cb9135a9 + ec030fdef9faf8b2bd6f5f422545e8d8f7054e48 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 5b7fc280e32618..4413d948f571ce 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -85,21 +85,21 @@ 8.0.100-preview.7.23329.3 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 2.5.1-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 - 8.0.0-beta.23429.1 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 2.5.1-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 + 8.0.0-beta.23431.2 6.0.0-preview.1.102 @@ -108,14 +108,14 @@ 8.0.0-rc.1.23406.6 8.0.0-preview.7.23325.2 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 6.0.0 1.1.1 @@ -222,38 +222,38 @@ 2.2.2 8.0.0-alpha.1.23412.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 - 8.0.0-rc.1.23415.5 + 8.0.0-rc.2.23431.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 - 16.0.5-alpha.1.23408.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23423.1 3.1.7 1.0.406601 diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index a88d643c8a765e..0998e875e5f78d 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -207,6 +207,7 @@ elseif(ILLUMOS) set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lssp") elseif(HAIKU) set(CMAKE_SYSROOT "${CROSS_ROOTFS}") + set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};${CROSS_ROOTFS}/cross-tools-x86_64/bin") set(TOOLSET_PREFIX ${TOOLCHAIN}-) function(locate_toolchain_exec exec var) @@ -217,7 +218,6 @@ elseif(HAIKU) endif() find_program(EXEC_LOCATION_${exec} - PATHS "${CROSS_ROOTFS}/cross-tools-x86_64/bin" NAMES "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}" "${TOOLSET_PREFIX}${exec}") diff --git a/global.json b/global.json index bdd818850a3add..dddad47ca24240 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23429.1", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23429.1", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23429.1", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23431.2", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23431.2", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23431.2", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From 3a811f41acfd65a9f0e53e85d533f49d9a444be1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 15:26:37 -0600 Subject: [PATCH 131/345] [release/8.0] Update dependencies from dotnet/roslyn (#91420) * Update dependencies from https://github.com/dotnet/roslyn build 20230831.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23430.6 -> To Version 4.8.0-3.23431.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230831.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23430.6 -> To Version 4.8.0-3.23431.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230831.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23430.6 -> To Version 4.8.0-3.23431.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230831.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23430.6 -> To Version 4.8.0-3.23431.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230901.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23430.6 -> To Version 4.8.0-3.23451.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5c942861fff1de..f54a2c3557aa74 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 0a5289acaadde17d768b8f69dbc35aeec74cc4f8 + 3686f3061a9202260a0de4d06e91855b0fa21e8c - + https://github.com/dotnet/roslyn - 0a5289acaadde17d768b8f69dbc35aeec74cc4f8 + 3686f3061a9202260a0de4d06e91855b0fa21e8c - + https://github.com/dotnet/roslyn - 0a5289acaadde17d768b8f69dbc35aeec74cc4f8 + 3686f3061a9202260a0de4d06e91855b0fa21e8c https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 4413d948f571ce..b1746d96b3472f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23430.6 - 4.8.0-3.23430.6 - 4.8.0-3.23430.6 + 4.8.0-3.23451.1 + 4.8.0-3.23451.1 + 4.8.0-3.23451.1 8.0.100-preview.7.23329.3 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 2.5.1-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 - 8.0.0-beta.23431.2 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 2.5.1-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 + 8.0.0-beta.23451.1 6.0.0-preview.1.102 @@ -209,15 +209,15 @@ 8.0.100-rc.1.23415.5 1.1.2-beta1.23323.1 - 7.0.0-preview-20221010.1 + 8.0.0-preview-20230828.1 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23428.2 + 0.11.4-alpha.23454.2 8.0.0-rc.1.23406.6 - 8.0.0-rc.2.23421.2 + 8.0.0-rc.2.23454.2 2.2.2 8.0.0-alpha.1.23412.1 @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.2.23431.1 + 8.0.0-rc.2.23455.4 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda diff --git a/global.json b/global.json index dddad47ca24240..6d208cff376c28 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23431.2", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23431.2", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23431.2", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23451.1", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23451.1", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23451.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From 1222f14d02818cfab597fa2a17c8664fe6cb39be Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 11:42:13 -0700 Subject: [PATCH 136/345] Enable output compilation validation in binder gen unit tests (#91602) Co-authored-by: Layomi Akinrinade --- .../tests/SourceGenerators/RoslynTestUtils.cs | 2 +- .../gen/Helpers/Emitter/Helpers.cs | 2 +- ...onfigurationServiceCollectionExtensions.cs | 5 +- .../Baselines/Collections.generated.txt | 2 +- .../ConfigurationBinder/Bind.generated.txt | 6 +- .../Bind_Instance.generated.txt | 2 +- .../Bind_Instance_BinderOptions.generated.txt | 2 +- .../Bind_Key_Instance.generated.txt | 2 +- .../ConfigurationBinder/Get.generated.txt | 8 +- .../GetValue.generated.txt | 8 +- .../GetValue_T_Key.generated.txt | 2 +- .../GetValue_T_Key_DefaultValue.generated.txt | 2 +- .../GetValue_TypeOf_Key.generated.txt | 2 +- ...alue_TypeOf_Key_DefaultValue.generated.txt | 2 +- .../ConfigurationBinder/Get_T.generated.txt | 2 +- .../Get_T_BinderOptions.generated.txt | 2 +- .../Get_TypeOf.generated.txt | 2 +- .../Get_TypeOf_BinderOptions.generated.txt | 2 +- .../BindConfiguration.generated.txt | 2 +- .../OptionsBuilder/Bind_T.generated.txt | 2 +- .../Bind_T_BinderOptions.generated.txt | 2 +- .../Baselines/Primitives.generated.txt | 25 ++- .../Configure_T.generated.txt | 3 +- .../Configure_T_BinderOptions.generated.txt | 3 +- .../Configure_T_name.generated.txt | 3 +- ...nfigure_T_name_BinderOptions.generated.txt | 3 +- .../GeneratorTests.Baselines.Options.cs | 2 +- .../GeneratorTests.Baselines.cs | 53 ++---- .../GeneratorTests.Helpers.cs | 171 ++++++++++++++++++ .../SourceGenerationTests/GeneratorTests.cs | 97 +--------- ...ation.Binder.SourceGeneration.Tests.csproj | 1 + 31 files changed, 245 insertions(+), 177 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs diff --git a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs index 2b4568a79eaba0..e67289721d8af9 100644 --- a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs +++ b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs @@ -91,7 +91,7 @@ public static async Task AssertNoDiagnostic(this Project proj, params string[] i } } - private static Project WithDocuments(this Project project, IEnumerable sources, IEnumerable? sourceNames = null) + public static Project WithDocuments(this Project project, IEnumerable sources, IEnumerable? sourceNames = null) { int count = 0; Project result = project; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index 909272c7678447..60ce9f681e077f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -142,7 +142,7 @@ private void EmitInterceptsLocationAnnotations(List inf { foreach (InterceptorLocationInfo info in infoList) { - _writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); + _writer.WriteLine($@"[{Identifier.InterceptsLocation}(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]"); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs index b811a8e6ae0eca..d89b124b0695fb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -85,9 +85,12 @@ @params[1].Type.SpecialType is SpecialType.System_String && private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec) { + RegisterTypeForBindCoreMainGen(typeSpec); + _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); - RegisterTypeForBindCoreMainGen(typeSpec); + // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource, IConfigureOptions<>, ConfigureNamedOptions<>. + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index 5f186e42e4da7d..775d9052ded435 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -32,7 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 12, 17)] + [InterceptsLocation(@"src-0.cs", 12, 17)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index 8d1f02b4e62e11..e5b37775cffd4b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + [InterceptsLocation(@"src-0.cs", 12, 14)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) @@ -49,7 +49,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + [InterceptsLocation(@"src-0.cs", 13, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { if (configuration is null) @@ -67,7 +67,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 14, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index f3008878ca3c56..fc35d29e693349 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 19b955b6ea8bff..0d3eb884c966e2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index 8533828221175b..392533daea462f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { if (configuration is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index 4acbebff935bca..d0faaa8fc91513 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -31,19 +31,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 12, 38)] + [InterceptsLocation(@"src-0.cs", 12, 38)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 14, 36)] + [InterceptsLocation(@"src-0.cs", 14, 36)] public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 13, 36)] + [InterceptsLocation(@"src-0.cs", 13, 56)] public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 15, 36)] + [InterceptsLocation(@"src-0.cs", 15, 47)] public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt index e4bcaf6a9b7c95..bf7e64bd31f90c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt @@ -30,19 +30,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + [InterceptsLocation(@"src-0.cs", 13, 18)] public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 16, 24)] + [InterceptsLocation(@"src-0.cs", 16, 24)] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + [InterceptsLocation(@"src-0.cs", 14, 24)] public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 17, 24)] + [InterceptsLocation(@"src-0.cs", 17, 24)] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt index 2438cf530ca4ce..b86915b78303b2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + [InterceptsLocation(@"src-0.cs", 10, 20)] public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt index e6db24d522f3c9..697f710dff3027 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt index a36f9fafebcff8..b5a22e71ccefbf 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + [InterceptsLocation(@"src-0.cs", 10, 20)] public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt index 356f6bb1a933e2..4a4564796e562f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + [InterceptsLocation(@"src-0.cs", 11, 20)] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index fb5cf5e4b5ca31..0b7031b1da00ba 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 40)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index ac8e362b4e2e07..4c950a79266d11 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 40)] public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt index 5d0088b908162d..ca323c234b8485 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 51)] public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 9da3a3a22e9b7c..e4a376a0cb3257 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + [InterceptsLocation(@"src-0.cs", 11, 20)] public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index 96e389be895602..f3829683be2bb3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers the dependency injection container to bind against the obtained from the DI service provider. - [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] + [InterceptsLocation(@"src-0.cs", 12, 24)] public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureBinder = null) where TOptions : class { if (optionsBuilder is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index 9755ab0df00086..de6ea5a3b9e1c6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config) where TOptions : class { return Bind(optionsBuilder, config, configureBinder: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index 141d2d41f77f83..2c40ebf69c9b46 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { if (optionsBuilder is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 1fd82a86d72c0d..7d94145d42a511 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] + [InterceptsLocation(@"src-0.cs", 13, 16)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) @@ -50,7 +50,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #endregion IConfiguration extensions. #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22", "Prop28", "Prop29", "Prop30" }); public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { @@ -142,12 +142,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (configuration["Prop23"] is string value18) { - instance.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); + instance.Prop23 = ParseTimeSpan(value18, () => configuration.GetSection("Prop23").Path); } if (configuration["Prop24"] is string value19) { - instance.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); + instance.Prop24 = ParseGuid(value19, () => configuration.GetSection("Prop24").Path); } if (configuration["Prop25"] is string value20) @@ -187,7 +187,22 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (configuration["Prop22"] is string value27) { - instance.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); + instance.Prop22 = ParseTimeOnly(value27, () => configuration.GetSection("Prop22").Path); + } + + if (configuration["Prop28"] is string value28) + { + instance.Prop28 = ParseByteArray(value28, () => configuration.GetSection("Prop28").Path); + } + + if (configuration["Prop29"] is string value29) + { + instance.Prop29 = ParseInt(value29, () => configuration.GetSection("Prop29").Path); + } + + if (configuration["Prop30"] is string value30) + { + instance.Prop30 = ParseDateTime(value30, () => configuration.GetSection("Prop30").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 0ff2de59156df9..973895e09fe55e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config) where TOptions : class { return Configure(services, string.Empty, config, configureOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index 7058edb884007f..08f233aff5503b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config, Action? configureOptions) where TOptions : class { return Configure(services, string.Empty, config, configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index a8f247779978ca..cb41ea860980a9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config) where TOptions : class { return Configure(services, name, config, configureOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 0cbd2fba049558..0a5e5a7ff6d26c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { if (services is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 0126744eacbfa4..c3d1ce89c1206f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -20,7 +20,7 @@ public static void Main() { ConfigurationBuilder configurationBuilder = new(); IConfiguration config = configurationBuilder.Build(); - IConfigurationSection section = config.GetSection(""MySection""); + IConfigurationSection section = config.GetSection("MySection"); ServiceCollection services = new(); services.Configure({{paramList}}); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 65e812d30b420f..7b3251e7fc85dc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -5,46 +5,15 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Xunit; namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { public partial class ConfigurationBindingGeneratorTests { - private const string BindCallSampleCode = @" - using System.Collections.Generic; - using Microsoft.Extensions.Configuration; - - public class Program - { - public static void Main() - { - ConfigurationBuilder configurationBuilder = new(); - IConfigurationRoot config = configurationBuilder.Build(); - - MyClass configObj = new(); - config.Bind(configObj); - config.Bind(configObj, options => { }); - config.Bind(""key"", configObj); - } - - public class MyClass - { - public string MyString { get; set; } - public int MyInt { get; set; } - public List MyList { get; set; } - public Dictionary MyDictionary { get; set; } - public Dictionary MyComplexDictionary { get; set; } - } - - public class MyClass2 { } - }"; - - [Theory] - [InlineData(LanguageVersion.Preview)] - public async Task Bind(LanguageVersion langVersion) => - await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); + [Fact] + public async Task Bind() => + await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, extType: ExtensionClassType.ConfigurationBinder); [Fact] public async Task Bind_Instance() @@ -163,9 +132,9 @@ public static void Main() IConfigurationRoot config = configurationBuilder.Build(); MyClass configObj = config.Get(); - configObj = config.Get(typeof(MyClass2)); + MyClass2 configObj2 = (MyClass2)config.Get(typeof(MyClass2)); configObj = config.Get(binderOptions => { }); - configObj = config.Get(typeof(MyClass2), binderOptions => { }); + configObj2 = (MyClass2)config.Get(typeof(MyClass2), binderOptions => { }); } public class MyClass @@ -302,7 +271,7 @@ public static void Main() ConfigurationBuilder configurationBuilder = new(); IConfigurationRoot config = configurationBuilder.Build(); - MyClass configObj = config.Get(typeof(MyClass2)); + MyClass2 configObj = (MyClass2)config.Get(typeof(MyClass2)); } public class MyClass @@ -590,9 +559,9 @@ public class MyClass public UInt128 Prop12 { get; set; } public DateOnly Prop18 { get; set; } public TimeOnly Prop22 { get; set; } - public byte[] Prop22 { get; set; } - public int Prop23 { get; set; } - public DateTime Prop24 { get; set; } + public byte[] Prop28 { get; set; } + public int Prop29 { get; set; } + public DateTime Prop30 { get; set; } } } """; @@ -613,7 +582,7 @@ public static void Main() { ConfigurationBuilder configurationBuilder = new(); IConfiguration config = configurationBuilder.Build(); - IConfigurationSection section = config.GetSection(""MySection""); + IConfigurationSection section = config.GetSection("MySection"); section.Get(); } @@ -647,7 +616,7 @@ public interface ICustomSet : ISet } """; - await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => + await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, validateOutputCompDiags: false, assessDiagnostics: (d) => { Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs new file mode 100644 index 00000000000000..d8818bcf3c1d4c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -0,0 +1,171 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Binder.SourceGeneration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using SourceGenerators.Tests; +using Xunit; + +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests +{ + public partial class ConfigurationBindingGeneratorTests + { + private const string BindCallSampleCode = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind(configObj); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + } + + public class MyClass2 { } + } + """; + + private static class Diagnostics + { + public static (string Id, string Title) TypeNotSupported = ("SYSLIB1100", "Did not generate binding logic for a type"); + public static (string Id, string Title) PropertyNotSupported = ("SYSLIB1101", "Did not generate binding logic for a property on a type"); + public static (string Id, string Title) ValueTypesInvalidForBind = ("SYSLIB1103", "Value types are invalid inputs to configuration 'Bind' methods"); + public static (string Id, string Title) CouldNotDetermineTypeInfo = ("SYSLIB1104", "The target type for a binder call could not be determined"); + } + + private static readonly Assembly[] s_compilationAssemblyRefs = new[] { + typeof(ConfigurationBinder).Assembly, + typeof(ConfigurationBuilder).Assembly, + typeof(CultureInfo).Assembly, + typeof(Dictionary<,>).Assembly, + typeof(Enumerable).Assembly, + typeof(IConfiguration).Assembly, + typeof(IServiceCollection).Assembly, + typeof(IServiceProvider).Assembly, + typeof(IDictionary).Assembly, + typeof(OptionsBuilder<>).Assembly, + typeof(OptionsConfigurationServiceCollectionExtensions).Assembly, + typeof(Uri).Assembly, + }; + + private enum ExtensionClassType + { + None, + ConfigurationBinder, + OptionsBuilder, + ServiceCollection, + } + + private static async Task VerifyAgainstBaselineUsingFile( + string filename, + string testSourceCode, + Action>? assessDiagnostics = null, + ExtensionClassType extType = ExtensionClassType.None, + bool validateOutputCompDiags = true) + { + string path = extType is ExtensionClassType.None + ? Path.Combine("Baselines", filename) + : Path.Combine("Baselines", extType.ToString(), filename); + string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); + string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) + .Split(Environment.NewLine); + + var (d, r) = await RunGenerator(testSourceCode, validateOutputCompDiags); + bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); + +#if UPDATE_BASELINES + if (!success) + { + string? repoRootDir = Environment.GetEnvironmentVariable("RepoRootDir"); + Assert.True(repoRootDir is not null, "To update baselines, specifiy the root runtime repo dir"); + + IEnumerable lines = r[0].SourceText.Lines.Select(l => l.ToString()); + string source = string.Join(Environment.NewLine, lines).TrimEnd(Environment.NewLine.ToCharArray()) + Environment.NewLine; + path = Path.Combine($"{repoRootDir}\\src\\libraries\\Microsoft.Extensions.Configuration.Binder\\tests\\SourceGenerationTests\\", path); + + await File.WriteAllTextAsync(path, source).ConfigureAwait(false); + success = true; + } +#endif + + Assert.Single(r); + (assessDiagnostics ?? ((d) => Assert.Empty(d))).Invoke(d); + Assert.True(success, errorMessage); + } + + private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( + string testSourceCode, + bool validateOutputCompDiags = false, + LanguageVersion langVersion = LanguageVersion.CSharp12, + IEnumerable? references = null) + { + using var workspace = RoslynTestUtils.CreateTestWorkspace(); + CSharpParseOptions parseOptions = new CSharpParseOptions(langVersion).WithFeatures(new[] { new KeyValuePair("InterceptorsPreview", "") }); + + Project proj = RoslynTestUtils.CreateTestProject(workspace, references ?? s_compilationAssemblyRefs, langVersion: langVersion) + .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Annotations)) + .WithDocuments(new string[] { testSourceCode }) + .WithParseOptions(parseOptions); + + Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution)); + + Compilation comp = await proj.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false); + CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { new ConfigurationBindingGenerator().AsSourceGenerator() }, parseOptions: parseOptions); + GeneratorDriver gd = cgd.RunGeneratorsAndUpdateCompilation(comp, out Compilation outputCompilation, out _, CancellationToken.None); + GeneratorDriverRunResult runResult = gd.GetRunResult(); + + if (validateOutputCompDiags) + { + Assert.False(outputCompilation.GetDiagnostics().Any(d => d.Severity > DiagnosticSeverity.Info)); + } + + return (runResult.Results[0].Diagnostics, runResult.Results[0].GeneratedSources); + } + + public static List GetAssemblyRefsWithAdditional(params Type[] additional) + { + List assemblies = new(s_compilationAssemblyRefs); + assemblies.AddRange(additional.Select(t => t.Assembly)); + return assemblies; + } + + public static HashSet GetFilteredAssemblyRefs(IEnumerable exclusions) + { + HashSet assemblies = new(s_compilationAssemblyRefs); + foreach (Type exclusion in exclusions) + { + assemblies.Remove(exclusion.Assembly); + } + return assemblies; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 33a4d04834b57a..3fddad379397ef 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -6,19 +6,15 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; -using System.IO; using System.Linq; -using System.Reflection; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Configuration.Binder.SourceGeneration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using SourceGenerators.Tests; using Xunit; namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests @@ -26,39 +22,12 @@ namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase { - private static class Diagnostics - { - public static (string Id, string Title) TypeNotSupported = ("SYSLIB1100", "Did not generate binding logic for a type"); - public static (string Id, string Title) PropertyNotSupported = ("SYSLIB1101", "Did not generate binding logic for a property on a type"); - public static (string Id, string Title) ValueTypesInvalidForBind = ("SYSLIB1103", "Value types are invalid inputs to configuration 'Bind' methods"); - public static (string Id, string Title) CouldNotDetermineTypeInfo = ("SYSLIB1104", "The target type for a binder call could not be determined"); - } - - private static readonly Assembly[] s_compilationAssemblyRefs = new[] { - typeof(ConfigurationBinder).Assembly, - typeof(CultureInfo).Assembly, - typeof(IConfiguration).Assembly, - typeof(IServiceCollection).Assembly, - typeof(IDictionary).Assembly, - typeof(OptionsBuilder<>).Assembly, - typeof(OptionsConfigurationServiceCollectionExtensions).Assembly, - typeof(Uri).Assembly, - }; - - private enum ExtensionClassType - { - None, - ConfigurationBinder, - OptionsBuilder, - ServiceCollection, - } - [Theory] [InlineData(LanguageVersion.CSharp11)] [InlineData(LanguageVersion.CSharp10)] public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion) { - var (d, r) = await RunGenerator(BindCallSampleCode, langVersion); + var (d, r) = await RunGenerator(BindCallSampleCode, langVersion: langVersion); Assert.Empty(r); Diagnostic diagnostic = Assert.Single(d); @@ -371,69 +340,5 @@ public class AnotherGraphWithUnsupportedMembers Assert.Equal(12, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(10, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); } - - private static async Task VerifyAgainstBaselineUsingFile( - string filename, - string testSourceCode, - LanguageVersion languageVersion = LanguageVersion.Preview, - Action>? assessDiagnostics = null, - ExtensionClassType extType = ExtensionClassType.None) - { - string path = extType is ExtensionClassType.None - ? Path.Combine("Baselines", filename) - : Path.Combine("Baselines", extType.ToString(), filename); - string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); - string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) - .Split(Environment.NewLine); - - var (d, r) = await RunGenerator(testSourceCode, languageVersion); - bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); - -#if UPDATE_BASELINES - if (!success) - { - string? repoRootDir = Environment.GetEnvironmentVariable("RepoRootDir"); - Assert.True(repoRootDir is not null, "To update baselines, specifiy the root runtime repo dir"); - - IEnumerable lines = r[0].SourceText.Lines.Select(l => l.ToString()); - string source = string.Join(Environment.NewLine, lines).TrimEnd(Environment.NewLine.ToCharArray()) + Environment.NewLine; - path = Path.Combine($"{repoRootDir}\\src\\libraries\\Microsoft.Extensions.Configuration.Binder\\tests\\SourceGenerationTests\\", path); - - await File.WriteAllTextAsync(path, source).ConfigureAwait(false); - success = true; - } -#endif - - Assert.Single(r); - (assessDiagnostics ?? ((d) => Assert.Empty(d))).Invoke(d); - Assert.True(success, errorMessage); - } - - private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( - string testSourceCode, - LanguageVersion langVersion = LanguageVersion.Preview, - IEnumerable? references = null) => - await RoslynTestUtils.RunGenerator( - new ConfigurationBindingGenerator(), - references ?? s_compilationAssemblyRefs, - new[] { testSourceCode }, - langVersion: langVersion).ConfigureAwait(false); - - public static List GetAssemblyRefsWithAdditional(params Type[] additional) - { - List assemblies = new(s_compilationAssemblyRefs); - assemblies.AddRange(additional.Select(t => t.Assembly)); - return assemblies; - } - - public static HashSet GetFilteredAssemblyRefs(IEnumerable exclusions) - { - HashSet assemblies = new(s_compilationAssemblyRefs); - foreach (Type exclusion in exclusions) - { - assemblies.Remove(exclusion.Assembly); - } - return assemblies; - } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 94d95564a47352..49ee1c1f968c06 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -54,6 +54,7 @@ + From e500806c224cb58328936133ca7a7bde896b514c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 12:52:57 -0700 Subject: [PATCH 137/345] [release/8.0] Enable interceptors implicitly in binder gen nupkg when generator is enabled (#91559) * Enable interceptors implicitly in binder gen nupkg when generator is enabled * Simplify impl & remove unneeded target --------- Co-authored-by: Layomi Akinrinade --- .../Microsoft.Extensions.Configuration.Binder.targets | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/buildTransitive/Microsoft.Extensions.Configuration.Binder.targets b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/buildTransitive/Microsoft.Extensions.Configuration.Binder.targets index f091c7a57b23ae..fdfd48d12a75ad 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/buildTransitive/Microsoft.Extensions.Configuration.Binder.targets +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/buildTransitive/Microsoft.Extensions.Configuration.Binder.targets @@ -1,5 +1,10 @@ - + + $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration + + + @@ -8,8 +13,8 @@ - + <_Microsoft_Extensions_Configuration_Binder_Compatible_TargetFramework Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netcoreapp2.0')) AND From b40f21207a12c813069e03eecf16af4e378b4b4c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:54:27 -0700 Subject: [PATCH 138/345] [release/8.0] Add late binding lookup in VB.NET for COM objects (#91433) * Add late binding lookup in VB.NET for COM objects * Review feedback * Feedback --------- Co-authored-by: Aaron R Robinson --- .../CompilerServices/NewLateBinding.vb | 33 +++++++++++++++++-- .../VisualBasic/CompilerServices/Symbols.vb | 6 ++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb b/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb index de0bde5e73a2f0..5d2f624b7a6b93 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb +++ b/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb @@ -47,6 +47,10 @@ Namespace Microsoft.VisualBasic.CompilerServices baseReference = New Container(Instance) End If + If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then + Return LateBinding.InternalLateCall(Instance, Type, MemberName, Arguments, ArgumentNames, CopyBack, IgnoreReturn) + End If + Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance) If idmop IsNot Nothing AndAlso TypeArguments Is NoTypeArguments Then Return IDOBinder.IDOCall(idmop, MemberName, Arguments, ArgumentNames, CopyBack, IgnoreReturn) @@ -139,7 +143,7 @@ Namespace Microsoft.VisualBasic.CompilerServices ' LateCallInvokeDefault is used to optionally invoke the default action on a call target. ' If the arguments are non-empty, then it isn't optional, and is treated ' as an error if there is no default action. - ' Currently we can get here only in the process of execution of NewLateBinding.LateCall. + ' Currently we can get here only in the process of execution of NewLateBinding.LateCall. @@ -155,7 +159,7 @@ Namespace Microsoft.VisualBasic.CompilerServices ' LateGetInvokeDefault is used to optionally invoke the default action. ' If the arguments are non-empty, then it isn't optional, and is treated ' as an error if there is no default action. - ' Currently we can get here only in the process of execution of NewLateBinding.LateGet. + ' Currently we can get here only in the process of execution of NewLateBinding.LateGet. @@ -167,7 +171,7 @@ Namespace Microsoft.VisualBasic.CompilerServices ' According to a comment in VBGetBinder.FallbackInvoke, this function is called when ' "The DLR was able to resolve o.member, but not o.member(args)" - ' When NewLateBinding.LateGet is evaluating similar expression itself, it never tries to invoke default action + ' When NewLateBinding.LateGet is evaluating similar expression itself, it never tries to invoke default action ' if arguments are not empty. It simply returns result of evaluating o.member. I believe, it makes sense ' to follow the same logic here. I.e., if there are no arguments, simply return the instance unless it is an IDO. @@ -278,6 +282,9 @@ Namespace Microsoft.VisualBasic.CompilerServices If argumentNames Is Nothing Then argumentNames = NoArgumentNames Dim baseReference As Container = New Container(instance) + If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then + Return LateBinding.LateIndexGet(instance, arguments, argumentNames) + End If 'An r-value expression o(a) has two possible forms: ' 1: o(a) array lookup--where o is an array object and a is a set of indices @@ -372,6 +379,10 @@ Namespace Microsoft.VisualBasic.CompilerServices baseReference = New Container(Instance) End If + If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then + Return LateBinding.LateGet(Instance, Type, MemberName, Arguments, ArgumentNames, CopyBack) + End If + Dim invocationFlags As BindingFlags = BindingFlagsInvokeMethod Or BindingFlagsGetProperty Dim idmop As IDynamicMetaObjectProvider = IDOUtils.TryCastToIDMOP(Instance) @@ -653,6 +664,10 @@ Namespace Microsoft.VisualBasic.CompilerServices End If Dim methodName As String = "" + If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then + LateBinding.LateIndexSetComplex(instance, arguments, argumentNames, optimisticSet, rValueBase) + Return + End If Dim invocationFlags As BindingFlags = BindingFlagsSetProperty @@ -927,6 +942,18 @@ Namespace Microsoft.VisualBasic.CompilerServices baseReference = New Container(Instance) End If + If baseReference.IsCOMObject AndAlso Not baseReference.IsWindowsRuntimeObject Then + Try + LateBinding.InternalLateSet(Instance, Type, MemberName, Arguments, ArgumentNames, OptimisticSet, CallType) + If RValueBase And Type.IsValueType Then + Throw New Exception(Utils.GetResourceString(SR.RValueBaseForValueType, baseReference.VBFriendlyName, baseReference.VBFriendlyName)) + End If + Return + Catch ex As MissingMemberException When OptimisticSet + Return + End Try + End If + Dim invocationFlags As BindingFlags ' If we have a IDO that implements TryGetMember for a property but not TrySetMember then we could land up diff --git a/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/Symbols.vb b/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/Symbols.vb index 8301ee324af3fc..44c694595b35bb 100644 --- a/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/Symbols.vb +++ b/src/libraries/Microsoft.VisualBasic.Core/src/Microsoft/VisualBasic/CompilerServices/Symbols.vb @@ -823,6 +823,12 @@ Namespace Microsoft.VisualBasic.CompilerServices End Get End Property + Friend ReadOnly Property IsCOMObject() As Boolean + Get + Return _type.IsCOMObject + End Get + End Property + Friend ReadOnly Property VBFriendlyName() As String Get Return Utils.VBFriendlyName(_type, _instance) From da3500bb02343b1d0424c74ccdddbc592b5b3f4f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 08:18:26 -0700 Subject: [PATCH 139/345] Add Microsoft.Extensions.Options.SourceGeneration To TransitivePackage (#91700) Co-authored-by: Tarek Mahmoud Sayed --- .../src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj b/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj index 611ac6d7d33814..732c102bab245b 100644 --- a/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj +++ b/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj @@ -34,5 +34,8 @@ + From 49b266d7eb231affbe24cddb186f9f27fe98014a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Sep 2023 18:56:38 -0700 Subject: [PATCH 140/345] Split the informational version on both SemVer2 separators, not just '-'. (#91760) This fixes a build break found when we stabilize the package version (and the only separator in the informational version is '+' before the commit id) Co-authored-by: Jeremy Koritzinsky --- .../AnalyzerConfigOptionsExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs index c7cfc69972d337..65f188ae1f7175 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/AnalyzerConfigOptionsExtensions.cs @@ -20,8 +20,8 @@ public static class AnalyzerConfigOptionsExtensions // Parse from the informational version as that is the only version that always matches the TFM version // even in debug builds. private static readonly Version ThisAssemblyVersion = Version.Parse( - typeof(IncrementalGeneratorInitializationContextExtensions).Assembly - .GetCustomAttribute().InformationalVersion.Split('-')[0]); + typeof(AnalyzerConfigOptionsExtensions).Assembly + .GetCustomAttribute().InformationalVersion.Split('-', '+')[0]); public static TargetFrameworkSettings GetTargetFrameworkSettings(this AnalyzerConfigOptions options) { From 467e23ffb4242c2891dab28c1e548a4bc71ef065 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 07:42:45 -0700 Subject: [PATCH 141/345] JIT: Fix invalid memory barrier removal optimization (#91870) The ARM32/ARM64 backends have an optimization where they optimize out the latter of two subsequent memory barriers if no memory store/load has been seen between them. This optimization should not be allowed to remove memory barriers when a call has been seen. Fix #91732 Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/emitarm.cpp | 1 + src/coreclr/jit/emitarm64.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/coreclr/jit/emitarm.cpp b/src/coreclr/jit/emitarm.cpp index a0dc786782b0bc..784f797bc5efed 100644 --- a/src/coreclr/jit/emitarm.cpp +++ b/src/coreclr/jit/emitarm.cpp @@ -4850,6 +4850,7 @@ void emitter::emitIns_Call(EmitCallType callType, dispIns(id); appendToCurIG(id); + emitLastMemBarrier = nullptr; // Cannot optimize away future memory barriers } /***************************************************************************** diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index f01ad548d2ee04..ef1220e325e47c 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -8886,6 +8886,7 @@ void emitter::emitIns_Call(EmitCallType callType, dispIns(id); appendToCurIG(id); + emitLastMemBarrier = nullptr; // Cannot optimize away future memory barriers } /***************************************************************************** From 1ce9687c01aa45348ba72853676d1e05178f372b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 07:44:55 -0700 Subject: [PATCH 142/345] [release/8.0] JIT: Fix invalid zero-init suppression for untracked variables (#91840) * JIT: Fix invalid zero-init supression for untracked variables optRemoveRedundantZeroInits has logic to remove unnecessary zero inits if we can determine that the local will be zeroed in the prolog. In addition, it also has logic to suppress the prolog zero init if there is a dominating initialization already. The latter logic was trying to reason about liveness for untracked locals, which does not make sense. Fix #91576 * Make EH succ logic less conservative --------- Co-authored-by: Jakob Botsch Nielsen Co-authored-by: Jeff Schwartz --- src/coreclr/jit/optimizer.cpp | 16 +++--- .../JitBlue/Runtime_91576/Runtime_91576.cs | 51 +++++++++++++++++++ .../Runtime_91576/Runtime_91576.csproj | 8 +++ 3 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.csproj diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 684f71b898f313..7c99a6a423dd01 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -9031,9 +9031,9 @@ void Compiler::optRemoveRedundantZeroInits() CompAllocator allocator(getAllocator(CMK_ZeroInit)); LclVarRefCounts refCounts(allocator); BitVecTraits bitVecTraits(lvaCount, this); - BitVec zeroInitLocals = BitVecOps::MakeEmpty(&bitVecTraits); - bool hasGCSafePoint = false; - bool canThrow = false; + BitVec zeroInitLocals = BitVecOps::MakeEmpty(&bitVecTraits); + bool hasGCSafePoint = false; + bool hasImplicitControlFlow = false; assert(fgNodeThreading == NodeThreading::AllTrees); @@ -9044,6 +9044,8 @@ void Compiler::optRemoveRedundantZeroInits() CompAllocator allocator(getAllocator(CMK_ZeroInit)); LclVarRefCounts defsInBlock(allocator); bool removedTrackedDefs = false; + bool hasEHSuccs = block->HasPotentialEHSuccs(this); + for (Statement* stmt = block->FirstNonPhiDef(); stmt != nullptr;) { Statement* next = stmt->GetNextStmt(); @@ -9054,10 +9056,7 @@ void Compiler::optRemoveRedundantZeroInits() hasGCSafePoint = true; } - if ((tree->gtFlags & GTF_EXCEPT) != 0) - { - canThrow = true; - } + hasImplicitControlFlow |= hasEHSuccs && ((tree->gtFlags & GTF_EXCEPT) != 0); switch (tree->gtOper) { @@ -9203,7 +9202,8 @@ void Compiler::optRemoveRedundantZeroInits() } } - if (!removedExplicitZeroInit && isEntire && (!canThrow || !lclDsc->lvLiveInOutOfHndlr)) + if (!removedExplicitZeroInit && isEntire && + (!hasImplicitControlFlow || (lclDsc->lvTracked && !lclDsc->lvLiveInOutOfHndlr))) { // If compMethodRequiresPInvokeFrame() returns true, lower may later // insert a call to CORINFO_HELP_INIT_PINVOKE_FRAME which is a gc-safe point. diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs new file mode 100644 index 00000000000000..4df185d99ab241 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license.aa + +// Generated by Fuzzlyn v1.6 on 2023-09-03 15:59:01 +// Run on X64 Windows +// Seed: 11520325105937570553 +// Reduced from 294.5 KiB to 0.7 KiB in 00:04:32 +// Debug: Outputs False +// Release: Outputs True +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_91576 +{ + [Fact] + public static int TestEntryPoint() + { + Assert.Throws(() => + { + Run(new int[1]); + Run(null); + }); + + return s_result; + } + + static int s_result; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Run(int[] l) + { + bool b = false; + try + { + int result = l[0]; + b = true; + } + finally + { + Check(ref b); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Check(ref bool b) + { + s_result = b ? 101 : 100; + } +} + diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From dbec2046adc49de5970af5a4482e68c06c4f39d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 07:45:57 -0700 Subject: [PATCH 143/345] [release/8.0] JIT: Handle mistyped commas in morph in pre-order too (#91718) * JIT: Compensate for mistyped commas in morph pre-order too Morph has post-order logic to compensate for mistyped commas produced by impStoreStruct. However, block morphing can optimize unused stores into INDs; this interacts with the mistyped commas to produce illegal IR shapes (e.g. `COMMA(..., IND(...))`). The ideal solution is to fix impStoreStruct (#91586 tracks this), but this change has a more surgical fix for the problem that can be backported to .NET 8. Fix #91443 * Fix build --------- Co-authored-by: Jakob Botsch Nielsen Co-authored-by: Jeff Schwartz --- src/coreclr/jit/morph.cpp | 8 +++++++ .../JitBlue/Runtime_91443/Runtime_91443.cs | 23 +++++++++++++++++++ .../Runtime_91443/Runtime_91443.csproj | 8 +++++++ 3 files changed, 39 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.csproj diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 52454b0c8b7316..153f9b8bba8a82 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8919,6 +8919,14 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA break; #endif + case GT_COMMA: + if (op2->OperIsStore() || (op2->OperGet() == GT_COMMA && op2->TypeGet() == TYP_VOID) || fgIsThrow(op2)) + { + typ = tree->gtType = TYP_VOID; + } + + break; + default: break; } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.cs new file mode 100644 index 00000000000000..d3844b77271dd7 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Numerics; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_91443 +{ + [Fact] + public static void TestEntryPoint() + { + new Runtime_91443().Method0(); + } + + static Vector3 s; + + [MethodImpl(MethodImplOptions.NoInlining)] + private void Method0() + { + Vector3.Cross(s, s); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91443/Runtime_91443.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From af44ecbcf83fcae54acfd0d34032ecc7fab6e633 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 07:47:18 -0700 Subject: [PATCH 144/345] [release/8.0] Emit less metadata for not-reflection-visible types (#91703) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Emit less metadata for not-reflection-visible types In .NET 8 we massively regressed the size of an empty WinForms app. A WinForms app now brings in a big chunk of WPF with it. I traced it down to the `ICommand` interface having a WPF `TypeConverter` and `ValueSerializer` attribute on it: https://github.com/dotnet/runtime/blob/04bd438844482c907062583153a43a9e3b37dbb8/src/libraries/System.ObjectModel/src/System/Windows/Input/ICommand.cs#L13-L16. An empty app will have a call to a method on `ICommand`, but nothing actually implements `ICommand`. Previously this would mean we generate an unconstructed `MethodTable` for `ICommand`, the unconstructed `MethodTable`s get no reflection metadata, and that's the end of the story. After #85810 however, the reflection stack can no longer reason about `MethodTable`s that don't have reflection metadata, so we need to generate it. This means we end up with the custom attribute and all the reflection dataflow that comes out of it. But this metadata is not actually visible in trim safe apps (the only place where reflection could see these method tables in trim safe code is if they're used in a type comparison `x == typeof(Foo)` and we were able to optimize the method table to the unconstructed version because of that). So we can generate less of it and still get away with it. In this PR I'm adding support for skipping generation of custom attribute metadata for such types. The size of an empty WinForms app goes from 50-something MB to 20-something MB. I think we'll be able to further reduce this number to ~7 MB or less because 12 MB of this are embedded resources that look designer related. * CR feedback --------- Co-authored-by: Michal Strehovský Co-authored-by: Jeff Schwartz --- .../Compiler/DependencyAnalysis/EETypeNode.cs | 3 +- .../GenericDefinitionEETypeNode.cs | 2 +- .../DependencyAnalysis/NodeFactory.cs | 17 ++++++- .../DependencyAnalysis/TypeMetadataNode.cs | 49 ++++++++++--------- .../Compiler/MetadataManager.cs | 6 +-- .../Compiler/UsageBasedMetadataManager.cs | 10 ++-- .../TrimmingBehaviors/DeadCodeElimination.cs | 46 +++++++++++++++++ 7 files changed, 100 insertions(+), 33 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs index 61520b4bfadaff..cd1ef49a221477 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs @@ -625,7 +625,8 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact // Ask the metadata manager // if we have any dependencies due to presence of the EEType. - factory.MetadataManager.GetDependenciesDueToEETypePresence(ref dependencies, factory, _type); + bool isFullType = factory.MaximallyConstructableType(_type) == this; + factory.MetadataManager.GetDependenciesDueToEETypePresence(ref dependencies, factory, _type, isFullType); if (_type is MetadataType mdType) ModuleUseBasedDependencyAlgorithm.AddDependenciesDueToModuleUse(ref dependencies, factory, mdType.Module); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDefinitionEETypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDefinitionEETypeNode.cs index b42d93273e4686..2bf7672884de07 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDefinitionEETypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDefinitionEETypeNode.cs @@ -25,7 +25,7 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact DependencyList dependencyList = null; // Ask the metadata manager if we have any dependencies due to the presence of the EEType. - factory.MetadataManager.GetDependenciesDueToEETypePresence(ref dependencyList, factory, _type); + factory.MetadataManager.GetDependenciesDueToEETypePresence(ref dependencyList, factory, _type, isFullType: true); return dependencyList; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index fbb6c08e04006c..5bc64c02d2886c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -458,7 +458,12 @@ private void CreateNodeCaches() _typesWithMetadata = new NodeCache(type => { - return new TypeMetadataNode(type); + return new TypeMetadataNode(type, includeCustomAttributes: true); + }); + + _typesWithMetadataWithoutCustomAttributes = new NodeCache(type => + { + return new TypeMetadataNode(type, includeCustomAttributes: false); }); _methodsWithMetadata = new NodeCache(method => @@ -1156,6 +1161,16 @@ internal TypeMetadataNode TypeMetadata(MetadataType type) return _typesWithMetadata.GetOrAdd(type); } + private NodeCache _typesWithMetadataWithoutCustomAttributes; + + internal TypeMetadataNode TypeMetadataWithoutCustomAttributes(MetadataType type) + { + // These are only meaningful for UsageBasedMetadataManager. We should not have them + // in the dependency graph otherwise. + Debug.Assert(MetadataManager is UsageBasedMetadataManager); + return _typesWithMetadataWithoutCustomAttributes.GetOrAdd(type); + } + private NodeCache _methodsWithMetadata; internal MethodMetadataNode MethodMetadata(MethodDesc method) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs index de162987d508b3..8979feb1061ca9 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/TypeMetadataNode.cs @@ -24,11 +24,13 @@ namespace ILCompiler.DependencyAnalysis internal sealed class TypeMetadataNode : DependencyNodeCore { private readonly MetadataType _type; + private readonly bool _includeCustomAttributes; - public TypeMetadataNode(MetadataType type) + public TypeMetadataNode(MetadataType type, bool includeCustomAttributes) { Debug.Assert(type.IsTypeDefinition); _type = type; + _includeCustomAttributes = includeCustomAttributes; } public MetadataType Type => _type; @@ -37,13 +39,21 @@ public override IEnumerable GetStaticDependencies(NodeFacto { DependencyList dependencies = new DependencyList(); - CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ((EcmaType)_type)); + if (_includeCustomAttributes) + CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ((EcmaType)_type)); DefType containingType = _type.ContainingType; if (containingType != null) - dependencies.Add(factory.TypeMetadata((MetadataType)containingType), "Containing type of a reflectable type"); + { + TypeMetadataNode metadataNode = _includeCustomAttributes + ? factory.TypeMetadata((MetadataType)containingType) + : factory.TypeMetadataWithoutCustomAttributes((MetadataType)containingType); + dependencies.Add(metadataNode, "Containing type of a reflectable type"); + } else + { dependencies.Add(factory.ModuleMetadata(_type.Module), "Containing module of a reflectable type"); + } var mdManager = (UsageBasedMetadataManager)factory.MetadataManager; @@ -100,7 +110,7 @@ public override IEnumerable GetStaticDependencies(NodeFacto /// Decomposes a constructed type into individual units that will be needed to /// express the constructed type in metadata. /// - public static void GetMetadataDependencies(ref DependencyList dependencies, NodeFactory nodeFactory, TypeDesc type, string reason) + public static void GetMetadataDependencies(ref DependencyList dependencies, NodeFactory nodeFactory, TypeDesc type, string reason, bool isFullType = true) { MetadataManager mdManager = nodeFactory.MetadataManager; @@ -110,13 +120,13 @@ public static void GetMetadataDependencies(ref DependencyList dependencies, Node case TypeFlags.SzArray: case TypeFlags.ByRef: case TypeFlags.Pointer: - GetMetadataDependencies(ref dependencies, nodeFactory, ((ParameterizedType)type).ParameterType, reason); + GetMetadataDependencies(ref dependencies, nodeFactory, ((ParameterizedType)type).ParameterType, reason, isFullType); break; case TypeFlags.FunctionPointer: var pointerType = (FunctionPointerType)type; - GetMetadataDependencies(ref dependencies, nodeFactory, pointerType.Signature.ReturnType, reason); + GetMetadataDependencies(ref dependencies, nodeFactory, pointerType.Signature.ReturnType, reason, isFullType); foreach (TypeDesc paramType in pointerType.Signature) - GetMetadataDependencies(ref dependencies, nodeFactory, paramType, reason); + GetMetadataDependencies(ref dependencies, nodeFactory, paramType, reason, isFullType); break; case TypeFlags.SignatureMethodVariable: @@ -126,27 +136,22 @@ public static void GetMetadataDependencies(ref DependencyList dependencies, Node default: Debug.Assert(type.IsDefType); - TypeDesc typeDefinition = type.GetTypeDefinition(); + var typeDefinition = (MetadataType)type.GetTypeDefinition(); if (typeDefinition != type) { - if (mdManager.CanGenerateMetadata((MetadataType)typeDefinition)) - { - dependencies ??= new DependencyList(); - dependencies.Add(nodeFactory.TypeMetadata((MetadataType)typeDefinition), reason); - } - foreach (TypeDesc typeArg in type.Instantiation) { - GetMetadataDependencies(ref dependencies, nodeFactory, typeArg, reason); + GetMetadataDependencies(ref dependencies, nodeFactory, typeArg, reason, isFullType); } } - else + + if (mdManager.CanGenerateMetadata(typeDefinition)) { - if (mdManager.CanGenerateMetadata((MetadataType)type)) - { - dependencies ??= new DependencyList(); - dependencies.Add(nodeFactory.TypeMetadata((MetadataType)type), reason); - } + dependencies ??= new DependencyList(); + TypeMetadataNode node = isFullType + ? nodeFactory.TypeMetadata(typeDefinition) + : nodeFactory.TypeMetadataWithoutCustomAttributes(typeDefinition); + dependencies.Add(node, reason); } break; } @@ -154,7 +159,7 @@ public static void GetMetadataDependencies(ref DependencyList dependencies, Node protected override string GetName(NodeFactory factory) { - return "Reflectable type: " + _type.ToString(); + return $"Reflectable type: {_type}{(!_includeCustomAttributes ? " (No custom attributes)" : "")}"; } protected override void OnMarked(NodeFactory factory) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs index 8658068c1ebe4d..b62304f362c16c 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs @@ -478,13 +478,13 @@ protected virtual void GetMetadataDependenciesDueToReflectability(ref Dependency /// /// This method is an extension point that can provide additional metadata-based dependencies to generated EETypes. /// - public virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + public virtual void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type, bool isFullType) { MetadataCategory category = GetMetadataCategory(type); if ((category & MetadataCategory.Description) != 0) { - GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type); + GetMetadataDependenciesDueToReflectability(ref dependencies, factory, type, isFullType); } } @@ -493,7 +493,7 @@ internal virtual void GetDependenciesDueToModuleUse(ref DependencyList dependenc // MetadataManagers can override this to provide additional dependencies caused by using a module } - protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + protected virtual void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type, bool isFullType) { // MetadataManagers can override this to provide additional dependencies caused by the emission of metadata // (E.g. dependencies caused by the type having custom attributes applied to it: making sure we compile the attribute constructor diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index e680bf80f2dfa7..fc0249f76847e5 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -271,9 +271,9 @@ internal override void GetDependenciesDueToModuleUse(ref DependencyList dependen } } - protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + protected override void GetMetadataDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, TypeDesc type, bool isFullType) { - TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, type, "Reflectable type"); + TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, type, "Reflectable type", isFullType); if (type.IsDelegate) { @@ -385,9 +385,9 @@ private static bool IsTrimmableAssembly(ModuleDesc assembly) return false; } - public override void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type) + public override void GetDependenciesDueToEETypePresence(ref DependencyList dependencies, NodeFactory factory, TypeDesc type, bool isFullType) { - base.GetDependenciesDueToEETypePresence(ref dependencies, factory, type); + base.GetDependenciesDueToEETypePresence(ref dependencies, factory, type, isFullType); DataflowAnalyzedTypeDefinitionNode.GetDependencies(ref dependencies, factory, FlowAnnotations, type); } @@ -970,7 +970,7 @@ public bool GeneratesMetadata(MethodDesc methodDef) public bool GeneratesMetadata(MetadataType typeDef) { - return _factory.TypeMetadata(typeDef).Marked; + return _factory.TypeMetadata(typeDef).Marked || _factory.TypeMetadataWithoutCustomAttributes(typeDef).Marked; } public bool GeneratesMetadata(EcmaModule module, CustomAttributeHandle caHandle) diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs index 152c8514556660..e030b3a1de99ce 100644 --- a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/DeadCodeElimination.cs @@ -21,6 +21,7 @@ public static int Run() TestStaticVirtualMethodOptimizations.Run(); TestTypeEquals.Run(); TestBranchesInGenericCodeRemoval.Run(); + TestLimitedMetadataBlobs.Run(); return 100; } @@ -378,6 +379,51 @@ public static void Run() } } + class TestLimitedMetadataBlobs + { + class MyAttribute : Attribute + { + public MyAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type t) { } + } + + class ShouldNotBeNeeded + { + } + + [My(typeof(ShouldNotBeNeeded))] + interface INeverImplemented + { + void Never(); + } + + static INeverImplemented s_instance; +#if !DEBUG + static Type s_type; +#endif + + internal static void Run() + { + Console.WriteLine("Testing generation of limited metadata blobs"); + + // Force a reference to the interface from a dispatch cell + if (s_instance != null) + s_instance.Never(); + + // Following is for release only since it relies on optimizing the typeof into an unconstructed + // MethodTable. +#if !DEBUG + // Force another reference from an LDTOKEN + if (s_type == typeof(INeverImplemented)) + s_type = typeof(object); +#endif + + ThrowIfPresent(typeof(TestLimitedMetadataBlobs), nameof(ShouldNotBeNeeded)); + ThrowIfPresent(typeof(TestLimitedMetadataBlobs), nameof(MyAttribute)); + ThrowIfNotPresent(typeof(TestLimitedMetadataBlobs), nameof(INeverImplemented)); + } + } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "That's the point")] private static Type GetTypeSecretly(Type testType, string typeName) => testType.GetNestedType(typeName, BindingFlags.NonPublic | BindingFlags.Public); From 603e3cc01aea0027077858e64dbbc7cf8bfca3c4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:47:11 -0700 Subject: [PATCH 145/345] Remove DebugProxy from ClaimsIdentity and ClaimsPrincipal (#91680) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: David Cantú --- .../System/Security/Claims/ClaimsIdentity.cs | 22 ------------------- .../System/Security/Claims/ClaimsPrincipal.cs | 16 -------------- 2 files changed, 38 deletions(-) diff --git a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs index e0d82df3b7863f..4408b11cddf135 100644 --- a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs +++ b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs @@ -14,7 +14,6 @@ namespace System.Security.Claims /// An Identity that is represented by a set of claims. /// [DebuggerDisplay("{DebuggerToString(),nq}")] - [DebuggerTypeProxy(typeof(ClaimsIdentityDebugProxy))] public class ClaimsIdentity : IIdentity { private enum SerializationMask @@ -962,26 +961,5 @@ internal string DebuggerToString() return debugText; } - - private sealed class ClaimsIdentityDebugProxy - { - private readonly ClaimsIdentity _identity; - - public ClaimsIdentityDebugProxy(ClaimsIdentity identity) - { - _identity = identity; - } - - public ClaimsIdentity? Actor => _identity.Actor; - public string? AuthenticationType => _identity.AuthenticationType; - public object? BootstrapContext => _identity.BootstrapContext; - // List type has a friendly debugger view - public List Claims => new List(_identity.Claims); - public bool IsAuthenticated => _identity.IsAuthenticated; - public string? Label => _identity.Label; - public string? Name => _identity.Name; - public string NameClaimType => _identity.NameClaimType; - public string RoleClaimType => _identity.RoleClaimType; - } } } diff --git a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs index 13ee10f7f6f4e6..de8f7d89725c68 100644 --- a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs +++ b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs @@ -15,7 +15,6 @@ namespace System.Security.Claims /// Concrete IPrincipal supporting multiple claims-based identities /// [DebuggerDisplay("{DebuggerToString(),nq}")] - [DebuggerTypeProxy(typeof(ClaimsPrincipalDebugProxy))] public class ClaimsPrincipal : IPrincipal { private enum SerializationMask @@ -594,20 +593,5 @@ private string DebuggerToString() return $"Identities = {identitiesCount}, Claims = {claimsCount}"; } - - private sealed class ClaimsPrincipalDebugProxy - { - private readonly ClaimsPrincipal _principal; - - public ClaimsPrincipalDebugProxy(ClaimsPrincipal principal) - { - _principal = principal; - } - - // List type has a friendly debugger view - public List Claims => new List(_principal.Claims); - public List Identities => new List(_principal.Identities); - public IIdentity? Identity => _principal.Identity; - } } } From 282da2cd568a4e1429990d3257efbc3724b79fee Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 16:38:49 -0600 Subject: [PATCH 146/345] [release/8.0] Update dependencies from dotnet/roslyn (#91482) * Update dependencies from https://github.com/dotnet/roslyn build 20230901.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23451.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230901.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23451.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230901.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23451.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230904.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23454.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230905.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23455.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230905.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23455.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230905.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23455.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230905.11 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23455.11 * Update dependencies from https://github.com/dotnet/roslyn build 20230905.12 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23455.12 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.11 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.11 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.12 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.12 * Update dependencies from https://github.com/dotnet/roslyn build 20230906.13 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23456.13 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230907.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23457.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230908.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23458.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230909.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23459.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230909.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23451.1 -> To Version 4.8.0-3.23459.2 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 52a007513c2b51..5fea3f92af6736 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 3686f3061a9202260a0de4d06e91855b0fa21e8c + d080175cabfe297ebf079af099279b61913bcc28 - + https://github.com/dotnet/roslyn - 3686f3061a9202260a0de4d06e91855b0fa21e8c + d080175cabfe297ebf079af099279b61913bcc28 - + https://github.com/dotnet/roslyn - 3686f3061a9202260a0de4d06e91855b0fa21e8c + d080175cabfe297ebf079af099279b61913bcc28 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 7097377fb2510a..560db925f60625 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23451.1 - 4.8.0-3.23451.1 - 4.8.0-3.23451.1 + 4.8.0-3.23459.2 + 4.8.0-3.23459.2 + 4.8.0-3.23459.2 - 3.11.0-beta1.23425.3 - 8.0.0-preview.23425.3 + 3.11.0-beta1.23458.2 + 8.0.0-preview.23458.2 - 8.0.0-rc.2.23455.4 + 8.0.0-rc.2.23460.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From 217be6c5b81c38bcfdd8d014a3a0b4412b6c2c1c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:09:04 -0600 Subject: [PATCH 148/345] Fix implementation of NegotiateAuthentication.Wrap for Kerberos on Windows (#91311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Filip Navara Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- .../Net/NegotiateAuthenticationPal.Windows.cs | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs index 3dcb03bfd08f74..07e8dea22baa9c 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Windows.cs @@ -421,28 +421,32 @@ public override unsafe NegotiateAuthenticationStatusCode Wrap(ReadOnlySpan Debug.Assert(success); // alloc new output buffer if not supplied or too small - int resultSize = input.Length + sizes.cbMaxSignature; + int resultSize = input.Length + sizes.cbSecurityTrailer + sizes.cbBlockSize; Span outputBuffer = outputWriter.GetSpan(resultSize); // make a copy of user data for in-place encryption - input.CopyTo(outputBuffer.Slice(sizes.cbMaxSignature, input.Length)); + input.CopyTo(outputBuffer.Slice(sizes.cbSecurityTrailer, input.Length)); isEncrypted = requestEncryption; fixed (byte* outputPtr = outputBuffer) { // Prepare buffers TOKEN(signature), DATA and Padding. - Interop.SspiCli.SecBuffer* unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[2]; + Interop.SspiCli.SecBuffer* unmanagedBuffer = stackalloc Interop.SspiCli.SecBuffer[3]; Interop.SspiCli.SecBuffer* tokenBuffer = &unmanagedBuffer[0]; Interop.SspiCli.SecBuffer* dataBuffer = &unmanagedBuffer[1]; + Interop.SspiCli.SecBuffer* paddingBuffer = &unmanagedBuffer[2]; tokenBuffer->BufferType = SecurityBufferType.SECBUFFER_TOKEN; tokenBuffer->pvBuffer = (IntPtr)(outputPtr); - tokenBuffer->cbBuffer = sizes.cbMaxSignature; + tokenBuffer->cbBuffer = sizes.cbSecurityTrailer; dataBuffer->BufferType = SecurityBufferType.SECBUFFER_DATA; - dataBuffer->pvBuffer = (IntPtr)(outputPtr + sizes.cbMaxSignature); + dataBuffer->pvBuffer = (IntPtr)(outputPtr + sizes.cbSecurityTrailer); dataBuffer->cbBuffer = input.Length; + paddingBuffer->BufferType = SecurityBufferType.SECBUFFER_PADDING; + paddingBuffer->pvBuffer = (IntPtr)(outputPtr + sizes.cbSecurityTrailer + input.Length); + paddingBuffer->cbBuffer = sizes.cbBlockSize; - Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(2) + Interop.SspiCli.SecBufferDesc sdcInOut = new Interop.SspiCli.SecBufferDesc(3) { pBuffers = unmanagedBuffer }; @@ -460,7 +464,20 @@ public override unsafe NegotiateAuthenticationStatusCode Wrap(ReadOnlySpan }; } - outputWriter.Advance(tokenBuffer->cbBuffer + dataBuffer->cbBuffer); + // Compact the result + if (tokenBuffer->cbBuffer != sizes.cbSecurityTrailer) + { + outputBuffer.Slice(sizes.cbSecurityTrailer, dataBuffer->cbBuffer).CopyTo( + outputBuffer.Slice(tokenBuffer->cbBuffer, dataBuffer->cbBuffer)); + } + if (tokenBuffer->cbBuffer != sizes.cbSecurityTrailer || + paddingBuffer->cbBuffer != sizes.cbBlockSize) + { + outputBuffer.Slice(sizes.cbSecurityTrailer + input.Length, paddingBuffer->cbBuffer).CopyTo( + outputBuffer.Slice(tokenBuffer->cbBuffer + dataBuffer->cbBuffer, paddingBuffer->cbBuffer)); + } + + outputWriter.Advance(tokenBuffer->cbBuffer + dataBuffer->cbBuffer + paddingBuffer->cbBuffer); return NegotiateAuthenticationStatusCode.Completed; } } From ef67ba828e906e12f0a158765e4c20c564f45270 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:09:49 -0600 Subject: [PATCH 149/345] [release/8.0] Add Native AOT Pri0 test leg (#91373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Pri0 test leg * wip * hm * Update Comparer_get_Default.csproj * Revert "wip" This reverts commit af025c048145685352b70eb76894c6d6d1eca0c5. * Add failing JIT test to issues.targets --------- Co-authored-by: Michal Strehovský Co-authored-by: Andy Gocke --- .../runtime-extra-platforms-other.yml | 38 +++++++++++++++++++ .../Comparer_get_Default.csproj | 3 ++ src/tests/build.proj | 1 + src/tests/issues.targets | 3 ++ 4 files changed, 45 insertions(+) diff --git a/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml b/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml index 13d3352393fa7f..c279c318e34d59 100644 --- a/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml +++ b/eng/pipelines/extra-platforms/runtime-extra-platforms-other.yml @@ -193,6 +193,44 @@ jobs: eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), eq(variables['isRollingBuild'], true)) +# +# CoreCLR NativeAOT checked build and Pri0 tests +# Only when CoreCLR is changed +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: Checked + platforms: + - windows_x64 + - linux_x64 + variables: + - name: timeoutPerTestInMinutes + value: 60 + - name: timeoutPerTestCollectionInMinutes + value: 180 + jobParameters: + timeoutInMinutes: 240 + nameSuffix: NativeAOT_Pri0 + buildArgs: -s clr.aot+host.native+libs -rc $(_BuildConfig) -lc Release -hc Release + extraStepsTemplate: /eng/pipelines/coreclr/nativeaot-post-build-steps.yml + extraStepsParameters: + creator: dotnet-bot + testBuildArgs: 'nativeaot /p:IlcUseServerGc=false' + liveLibrariesBuildConfig: Release + testRunNamePrefixSuffix: NativeAOT_Pri0_$(_BuildConfig) + extraVariablesTemplates: + - template: /eng/pipelines/common/templates/runtimes/test-variables.yml + parameters: + testGroup: innerloop + liveLibrariesBuildConfig: Release + condition: >- + or( + eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), + eq(variables['isRollingBuild'], true)) + # Run net48 tests on win-x64 - template: /eng/pipelines/common/platform-matrix.yml parameters: diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj index c6636e39772f44..ef9e4a7a6abc7c 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj @@ -1,6 +1,9 @@ True + + + true diff --git a/src/tests/build.proj b/src/tests/build.proj index 090f11df3acd5a..e49ddc0b51b2f8 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -595,6 +595,7 @@ $(GroupBuildCmd) "/p:CrossBuild=true" $(GroupBuildCmd) "/p:DefaultBuildAllTarget=BuildNativeAot" $(GroupBuildCmd) "/p:IlcMultiModule=true" + $(GroupBuildCmd) "/p:IlcUseServerGc=false" $(GroupBuildCmd) "/p:BuildNativeAotFrameworkObjects=true" diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 7ec7dc726f34ef..d950862b7fdbf2 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -694,6 +694,9 @@ + + https://github.com/dotnet/runtime/issues/90848 + https://github.com/dotnet/runtime/issues/89157 From acab656484c23d9c6e24ca3f77eb8234cb8100e1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:13:46 -0600 Subject: [PATCH 150/345] [release/8.0] Update dependencies from dnceng/internal/dotnet-optimization (#91501) * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230901.6 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23451.6 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230902.2 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23452.2 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230902.2 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23452.2 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230902.2 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23452.2 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230907.4 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23457.4 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230908.2 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23458.2 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230908.2 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23458.2 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230908.2 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23431.4 -> To Version 1.0.0-prerelease.23458.2 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 90223f37e1382b..942050ec170f13 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 4665b3d04e1da3796b965c3c3e3b97f55c449a6e - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 07f1da26c7bd97db0defad5e38bed5e514eb960e + 25dddd65cef2d69facd6cd646600e540d46fd6ec - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 07f1da26c7bd97db0defad5e38bed5e514eb960e + 25dddd65cef2d69facd6cd646600e540d46fd6ec - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 07f1da26c7bd97db0defad5e38bed5e514eb960e + 25dddd65cef2d69facd6cd646600e540d46fd6ec - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 07f1da26c7bd97db0defad5e38bed5e514eb960e + 25dddd65cef2d69facd6cd646600e540d46fd6ec https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 07f1da26c7bd97db0defad5e38bed5e514eb960e + 25dddd65cef2d69facd6cd646600e540d46fd6ec - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 07f1da26c7bd97db0defad5e38bed5e514eb960e + 25dddd65cef2d69facd6cd646600e540d46fd6ec diff --git a/eng/Versions.props b/eng/Versions.props index 10212c081a0dc9..f2a663cea35218 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23431.4 - 1.0.0-prerelease.23431.4 - 1.0.0-prerelease.23431.4 - 1.0.0-prerelease.23431.4 - 1.0.0-prerelease.23431.4 - 1.0.0-prerelease.23431.4 + 1.0.0-prerelease.23458.2 + 1.0.0-prerelease.23458.2 + 1.0.0-prerelease.23458.2 + 1.0.0-prerelease.23458.2 + 1.0.0-prerelease.23458.2 + 1.0.0-prerelease.23458.2 16.11.27-beta1.23180.1 2.0.0-beta4.23307.1 From 64c5aaede2e82c4f353d3cac7111b10ebced2dec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:17:44 -0600 Subject: [PATCH 151/345] [release/8.0] Fix Dispose and SendData Race on Http3 Test (#91690) * Fix Dispose and Send Data Race * Review feedback --------- Co-authored-by: Ahmet Ibrahim Aksoy (from Dev Box) --- .../tests/FunctionalTests/HttpClientHandlerTest.Http3.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs index 92c4ab0d6097f6..844d2866bde61e 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http3.cs @@ -1626,6 +1626,7 @@ public async Task DuplexStreaming_AbortByServer_StreamingCancelled(bool graceful public async Task ServerSendsTrailingHeaders_Success() { using Http3LoopbackServer server = CreateHttp3LoopbackServer(); + SemaphoreSlim clientFinishedSemaphore = new SemaphoreSlim(0); Task serverTask = Task.Run(async () => { @@ -1636,6 +1637,7 @@ public async Task ServerSendsTrailingHeaders_Success() await requestStream.ReadRequestDataAsync(); await requestStream.SendResponseAsync(isFinal: false); await requestStream.SendResponseHeadersAsync(null, new[] { new HttpHeaderData("MyHeader", "MyValue") }); + await clientFinishedSemaphore.WaitAsync(TimeSpan.FromSeconds(20)); }); Task clientTask = Task.Run(async () => @@ -1655,6 +1657,7 @@ public async Task ServerSendsTrailingHeaders_Success() (string key, IEnumerable value) = Assert.Single(response.TrailingHeaders); Assert.Equal("MyHeader", key); Assert.Equal("MyValue", Assert.Single(value)); + clientFinishedSemaphore.Release(); }); await new[] { clientTask, serverTask }.WhenAllOrAnyFailed(200_000); From bfdfb82ad34baa6381dc6cc22c4ec695aafa8525 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:18:32 -0600 Subject: [PATCH 152/345] [maccatalyst] Make sure MacProxy is included in System.Net.Http (#91599) https://github.com/dotnet/runtime/issues/90258 identified that `HttpClient.DefaultProxy` returned `System.Net.Http.HttpNoProxy` when using MacCatalyst. This is due to a condition in System.Net.Http.csproj not including maccatalyst as a condition and as a result, skipped adding the MacProxy sources. Way back when, https://github.com/dotnet/runtime/pull/47823 had the condition, but this appears to have changed in https://github.com/dotnet/runtime/pull/48652 when we thought MacCatalyst would inherit settings from iOS. That turned out to not be the case and this check was never added back. Co-authored-by: Steve Pfister --- src/libraries/System.Net.Http/src/System.Net.Http.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index f9c229575e1214..f263f9480cd67e 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -316,11 +316,11 @@ - + - + Date: Tue, 12 Sep 2023 01:19:43 +0200 Subject: [PATCH 153/345] Check DotNetFinalVersionKind when setting WorkloadVersionSuffix (#91791) --- eng/Versions.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index f2a663cea35218..646f22880d530d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -11,16 +11,16 @@ 6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11)) rc 2 - -$(PreReleaseVersionLabel).$(PreReleaseVersionIteration) + + false + release + -$(PreReleaseVersionLabel).$(PreReleaseVersionIteration) $(SdkBandVersion)$(WorkloadVersionSuffix) false $(MajorVersion).$(MinorVersion).0.0 - - false - release true false From 4147efb8b031eecd5776b6172f974e02b4972f56 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 12 Sep 2023 01:23:50 +0200 Subject: [PATCH 154/345] [release/8.0] JIT: DNER multiregs with SIMD12 (#91878) * JIT: DNER multiregs with SIMD12s Locals with SIMD12 fields will never match the ABI when they end up as multireg returns, so these should always be DNER'd. Fix #91214 * Fix test build --- src/coreclr/jit/lower.cpp | 22 ++++++++++ .../JitBlue/Runtime_91062/Runtime_91062.cs | 2 +- .../JitBlue/Runtime_91170/Runtime_91170.cs | 2 +- .../JitBlue/Runtime_91214/Runtime_91214.cs | 40 +++++++++++++++++++ .../Runtime_91214/Runtime_91214.csproj | 8 ++++ 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.csproj diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 81df694f05e1ff..2e454e64c14eb1 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -7484,6 +7484,28 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, int registerCount) if (registerCount == varDsc->lvFieldCnt) { canEnregisterAsMultiReg = true; + +#ifdef FEATURE_SIMD + // TYP_SIMD12 breaks the above invariant that "we won't have + // matching reg and field counts"; for example, consider + // + // * STORE_LCL_VAR(CALL) + // * RETURN(LCL_VAR) + // + // These return in two GPR registers, while the fields of the + // local are stored in SIMD and GPR register, so registerCount + // == varDsc->lvFieldCnt == 2. But the backend cannot handle + // this. + + for (int i = 0; i < varDsc->lvFieldCnt; i++) + { + if (comp->lvaGetDesc(varDsc->lvFieldLclStart + i)->TypeGet() == TYP_SIMD12) + { + canEnregisterAsMultiReg = false; + break; + } + } +#endif } } } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs index 8886bd2044ab04..562d2029ff85c5 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91062/Runtime_91062.cs @@ -1,5 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license.aa +// The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs index afb26b6def0bc0..7f3e9293eba974 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91170/Runtime_91170.cs @@ -1,5 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license.aa +// The .NET Foundation licenses this file to you under the MIT license. // Found by Antigen diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.cs new file mode 100644 index 00000000000000..d30adf6e60cf11 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Found by Antigen + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Numerics; +using Xunit; + +public class Runtime_91214 +{ + [Fact] + public static void TestEntryPoint() + { + Method0(); + } + + struct S + { + public Vector3 v3; + public bool b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static S Method2() + { + return default; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Method0() + { + S s = Method2(); + Log(null, s.v3); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Log(object a, object b) { } +} \ No newline at end of file diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91214/Runtime_91214.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 9819f182fdab5238be9971c76bdd0c3845c97a6b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:24:18 -0600 Subject: [PATCH 155/345] [release/8.0] Improve perf of ActivatorUtilities.CreateInstance() (#91881) * Improve perf of ActivatorUtilities.CreateInstance() * Support MetadataUpdateHandler for hot reload * Support unloadable assembly contexts * Add tests * Rename new test classes * Remove Mono from test; remove cache for NetFramework; remove use of ConstructorInvoker for possible risk of callstack usage * Misc naming etc; non-functional * Update some comments * Simplify use of ConditionalWeakTable.Add --------- Co-authored-by: Steve Harter --- .../src/ActivatorUtilities.cs | 227 ++++++++++++++---- .../CollectibleAssembly/CollectableClasses.cs | 25 ++ .../CollectibleAssembly.csproj | 11 + .../tests/DI.Tests/ActivatorUtilitiesTests.cs | 159 +++++++++++- ...xtensions.DependencyInjection.Tests.csproj | 3 +- 5 files changed, 372 insertions(+), 53 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectableClasses.cs create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectibleAssembly.csproj diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs index eb7931489b557e..6a42373ccc77d4 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Concurrent; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -10,6 +11,10 @@ using System.Runtime.ExceptionServices; using Microsoft.Extensions.Internal; +#if NETCOREAPP +[assembly: System.Reflection.Metadata.MetadataUpdateHandler(typeof(Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ActivatorUtilitiesUpdateHandler))] +#endif + namespace Microsoft.Extensions.DependencyInjection { /// @@ -17,6 +22,14 @@ namespace Microsoft.Extensions.DependencyInjection /// public static class ActivatorUtilities { +#if NETCOREAPP + // Support caching of constructor metadata for the common case of types in non-collectible assemblies. + private static readonly ConcurrentDictionary s_constructorInfos = new(); + + // Support caching of constructor metadata for types in collectible assemblies. + private static readonly Lazy> s_collectibleConstructorInfos = new(); +#endif + #if NET8_0_OR_GREATER // Maximum number of fixed arguments for ConstructorInvoker.Invoke(arg1, etc). private const int FixedArgumentThreshold = 4; @@ -47,6 +60,17 @@ public static object CreateInstance( throw new InvalidOperationException(SR.CannotCreateAbstractClasses); } + ConstructorInfoEx[]? constructors; +#if NETCOREAPP + if (!s_constructorInfos.TryGetValue(instanceType, out constructors)) + { + constructors = GetOrAddConstructors(instanceType); + } +#else + constructors = CreateConstructorInfoExs(instanceType); +#endif + + ConstructorInfoEx? constructor; IServiceProviderIsService? serviceProviderIsService = provider.GetService(); // if container supports using IServiceProviderIsService, we try to find the longest ctor that // (a) matches all parameters given to CreateInstance @@ -61,10 +85,11 @@ public static object CreateInstance( ConstructorMatcher bestMatcher = default; bool multipleBestLengthFound = false; - foreach (ConstructorInfo? constructor in instanceType.GetConstructors()) + for (int i = 0; i < constructors.Length; i++) { - var matcher = new ConstructorMatcher(constructor); - bool isPreferred = constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), false); + constructor = constructors[i]; + ConstructorMatcher matcher = new(constructor); + bool isPreferred = constructor.IsPreferred; int length = matcher.Match(parameters, serviceProviderIsService); if (isPreferred) @@ -105,18 +130,79 @@ public static object CreateInstance( } } - Type?[] argumentTypes = new Type[parameters.Length]; - for (int i = 0; i < argumentTypes.Length; i++) + Type?[] argumentTypes; + if (parameters.Length == 0) { - argumentTypes[i] = parameters[i]?.GetType(); + argumentTypes = Type.EmptyTypes; + } + else + { + argumentTypes = new Type[parameters.Length]; + for (int i = 0; i < argumentTypes.Length; i++) + { + argumentTypes[i] = parameters[i]?.GetType(); + } } FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructorInfo, out int?[] parameterMap); - var constructorMatcher = new ConstructorMatcher(constructorInfo); + + // Find the ConstructorInfoEx from the given constructorInfo. + constructor = null; + foreach (ConstructorInfoEx ctor in constructors) + { + if (ReferenceEquals(ctor.Info, constructorInfo)) + { + constructor = ctor; + break; + } + } + + Debug.Assert(constructor != null); + + var constructorMatcher = new ConstructorMatcher(constructor); constructorMatcher.MapParameters(parameterMap, parameters); return constructorMatcher.CreateInstance(provider); } +#if NETCOREAPP + private static ConstructorInfoEx[] GetOrAddConstructors( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + // Not found. Do the slower work of checking for the value in the correct cache. + // Null and non-collectible load contexts use the default cache. + if (!type.Assembly.IsCollectible) + { + return s_constructorInfos.GetOrAdd(type, CreateConstructorInfoExs(type)); + } + + // Collectible load contexts should use the ConditionalWeakTable so they can be unloaded. + if (s_collectibleConstructorInfos.Value.TryGetValue(type, out ConstructorInfoEx[]? value)) + { + return value; + } + + value = CreateConstructorInfoExs(type); + + // ConditionalWeakTable doesn't support GetOrAdd() so use AddOrUpdate(). This means threads + // can have different instances for the same type, but that is OK since they are equivalent. + s_collectibleConstructorInfos.Value.AddOrUpdate(type, value); + return value; + } +#endif // NETCOREAPP + + private static ConstructorInfoEx[] CreateConstructorInfoExs( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type) + { + ConstructorInfo[] constructors = type.GetConstructors(); + ConstructorInfoEx[]? value = new ConstructorInfoEx[constructors.Length]; + for (int i = 0; i < constructors.Length; i++) + { + value[i] = new ConstructorInfoEx(constructors[i]); + } + + return value; + } + /// /// Create a delegate that will instantiate a type with constructor arguments provided directly /// and/or from an . @@ -551,58 +637,82 @@ private static bool TryCreateParameterMap(ParameterInfo[] constructorParameters, return true; } - private static object? GetService(IServiceProvider serviceProvider, ParameterInfo parameterInfo) + private sealed class ConstructorInfoEx { - // Handle keyed service - if (TryGetServiceKey(parameterInfo, out object? key)) + public readonly ConstructorInfo Info; + public readonly ParameterInfo[] Parameters; + public readonly bool IsPreferred; + private readonly object?[]? _parameterKeys; + + public ConstructorInfoEx(ConstructorInfo constructor) { - if (serviceProvider is IKeyedServiceProvider keyedServiceProvider) + Info = constructor; + Parameters = constructor.GetParameters(); + IsPreferred = constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), inherit: false); + + for (int i = 0; i < Parameters.Length; i++) { - return keyedServiceProvider.GetKeyedService(parameterInfo.ParameterType, key); + FromKeyedServicesAttribute? attr = (FromKeyedServicesAttribute?) + Attribute.GetCustomAttribute(Parameters[i], typeof(FromKeyedServicesAttribute), inherit: false); + + if (attr is not null) + { + _parameterKeys ??= new object?[Parameters.Length]; + _parameterKeys[i] = attr.Key; + } } - throw new InvalidOperationException(SR.KeyedServicesNotSupported); } - // Try non keyed service - return serviceProvider.GetService(parameterInfo.ParameterType); - } - private static bool IsService(IServiceProviderIsService serviceProviderIsService, ParameterInfo parameterInfo) - { - // Handle keyed service - if (TryGetServiceKey(parameterInfo, out object? key)) + public bool IsService(IServiceProviderIsService serviceProviderIsService, int parameterIndex) { - if (serviceProviderIsService is IServiceProviderIsKeyedService serviceProviderIsKeyedService) + ParameterInfo parameterInfo = Parameters[parameterIndex]; + + // Handle keyed service + object? key = _parameterKeys?[parameterIndex]; + if (key is not null) { - return serviceProviderIsKeyedService.IsKeyedService(parameterInfo.ParameterType, key); + if (serviceProviderIsService is IServiceProviderIsKeyedService serviceProviderIsKeyedService) + { + return serviceProviderIsKeyedService.IsKeyedService(parameterInfo.ParameterType, key); + } + + throw new InvalidOperationException(SR.KeyedServicesNotSupported); } - throw new InvalidOperationException(SR.KeyedServicesNotSupported); + + // Use non-keyed service + return serviceProviderIsService.IsService(parameterInfo.ParameterType); } - // Try non keyed service - return serviceProviderIsService.IsService(parameterInfo.ParameterType); - } - private static bool TryGetServiceKey(ParameterInfo parameterInfo, out object? key) - { - foreach (var attribute in parameterInfo.GetCustomAttributes(false)) + public object? GetService(IServiceProvider serviceProvider, int parameterIndex) { - key = attribute.Key; - return true; + ParameterInfo parameterInfo = Parameters[parameterIndex]; + + // Handle keyed service + object? key = _parameterKeys?[parameterIndex]; + if (key is not null) + { + if (serviceProvider is IKeyedServiceProvider keyedServiceProvider) + { + return keyedServiceProvider.GetKeyedService(parameterInfo.ParameterType, key); + } + + throw new InvalidOperationException(SR.KeyedServicesNotSupported); + } + + // Use non-keyed service + return serviceProvider.GetService(parameterInfo.ParameterType); } - key = null; - return false; } private readonly struct ConstructorMatcher { - private readonly ConstructorInfo _constructor; - private readonly ParameterInfo[] _parameters; + private readonly ConstructorInfoEx _constructor; private readonly object?[] _parameterValues; - public ConstructorMatcher(ConstructorInfo constructor) + public ConstructorMatcher(ConstructorInfoEx constructor) { _constructor = constructor; - _parameters = _constructor.GetParameters(); - _parameterValues = new object?[_parameters.Length]; + _parameterValues = new object[constructor.Parameters.Length]; } public int Match(object[] givenParameters, IServiceProviderIsService serviceProviderIsService) @@ -612,10 +722,10 @@ public int Match(object[] givenParameters, IServiceProviderIsService serviceProv Type? givenType = givenParameters[givenIndex]?.GetType(); bool givenMatched = false; - for (int applyIndex = 0; applyIndex < _parameters.Length; applyIndex++) + for (int applyIndex = 0; applyIndex < _constructor.Parameters.Length; applyIndex++) { if (_parameterValues[applyIndex] == null && - _parameters[applyIndex].ParameterType.IsAssignableFrom(givenType)) + _constructor.Parameters[applyIndex].ParameterType.IsAssignableFrom(givenType)) { givenMatched = true; _parameterValues[applyIndex] = givenParameters[givenIndex]; @@ -630,12 +740,12 @@ public int Match(object[] givenParameters, IServiceProviderIsService serviceProv } // confirms the rest of ctor arguments match either as a parameter with a default value or as a service registered - for (int i = 0; i < _parameters.Length; i++) + for (int i = 0; i < _constructor.Parameters.Length; i++) { if (_parameterValues[i] == null && - !IsService(serviceProviderIsService, _parameters[i])) + !_constructor.IsService(serviceProviderIsService, i)) { - if (ParameterDefaultValue.TryGetDefaultValue(_parameters[i], out object? defaultValue)) + if (ParameterDefaultValue.TryGetDefaultValue(_constructor.Parameters[i], out object? defaultValue)) { _parameterValues[i] = defaultValue; } @@ -646,21 +756,21 @@ public int Match(object[] givenParameters, IServiceProviderIsService serviceProv } } - return _parameters.Length; + return _constructor.Parameters.Length; } public object CreateInstance(IServiceProvider provider) { - for (int index = 0; index < _parameters.Length; index++) + for (int index = 0; index < _constructor.Parameters.Length; index++) { if (_parameterValues[index] == null) { - object? value = GetService(provider, _parameters[index]); + object? value = _constructor.GetService(provider, index); if (value == null) { - if (!ParameterDefaultValue.TryGetDefaultValue(_parameters[index], out object? defaultValue)) + if (!ParameterDefaultValue.TryGetDefaultValue(_constructor.Parameters[index], out object? defaultValue)) { - throw new InvalidOperationException(SR.Format(SR.UnableToResolveService, _parameters[index].ParameterType, _constructor.DeclaringType)); + throw new InvalidOperationException(SR.Format(SR.UnableToResolveService, _constructor.Parameters[index].ParameterType, _constructor.Info.DeclaringType)); } else { @@ -677,7 +787,7 @@ public object CreateInstance(IServiceProvider provider) #if NETFRAMEWORK || NETSTANDARD2_0 try { - return _constructor.Invoke(_parameterValues); + return _constructor.Info.Invoke(_parameterValues); } catch (TargetInvocationException ex) when (ex.InnerException != null) { @@ -686,13 +796,13 @@ public object CreateInstance(IServiceProvider provider) throw; } #else - return _constructor.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: _parameterValues, culture: null); + return _constructor.Info.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: _parameterValues, culture: null); #endif } public void MapParameters(int?[] parameterMap, object[] givenParameters) { - for (int i = 0; i < _parameters.Length; i++) + for (int i = 0; i < _constructor.Parameters.Length; i++) { if (parameterMap[i] != null) { @@ -974,5 +1084,20 @@ private static object ReflectionFactoryCanonical( return constructor.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, constructorArguments, culture: null); } #endif // NET8_0_OR_GREATER + +#if NETCOREAPP + internal static class ActivatorUtilitiesUpdateHandler + { + public static void ClearCache(Type[]? _) + { + // Ignore the Type[] argument; just clear the caches. + s_constructorInfos.Clear(); + if (s_collectibleConstructorInfos.IsValueCreated) + { + s_collectibleConstructorInfos.Value.Clear(); + } + } + } +#endif } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectableClasses.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectableClasses.cs new file mode 100644 index 00000000000000..cc9e925ae0ad8e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectableClasses.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.DependencyInjection; + +namespace CollectibleAssembly +{ + public class ClassToCreate + { + public object ClassAsCtorArgument { get; set; } + + public ClassToCreate(ClassAsCtorArgument obj) { ClassAsCtorArgument = obj; } + + public static object Create(ServiceProvider provider) + { + // Both the type to create (ClassToCreate) and the ctor's arg type (ClassAsCtorArgument) are + // located in this assembly, so both types need to be GC'd for this assembly to be collected. + return ActivatorUtilities.CreateInstance(provider, new ClassAsCtorArgument()); + } + } + + public class ClassAsCtorArgument + { + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectibleAssembly.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectibleAssembly.csproj new file mode 100644 index 00000000000000..82159cece28227 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CollectibleAssembly/CollectibleAssembly.csproj @@ -0,0 +1,11 @@ + + + $(NetCoreAppCurrent);$(NetFrameworkMinimum) + true + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs index 7572e6977a4c49..dda3cafa442eb0 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs @@ -2,8 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.IO; +using System.Reflection; using Microsoft.DotNet.RemoteExecutor; using Xunit; +using System.Runtime.CompilerServices; + +#if NETCOREAPP +using System.Runtime.Loader; +#endif namespace Microsoft.Extensions.DependencyInjection.Tests { @@ -386,6 +393,125 @@ public void CreateFactory_RemoteExecutor_NoParameters_Success(bool useDynamicCod }, options); } +#if NETCOREAPP + [ActiveIssue("https://github.com/dotnet/runtime/issues/34072", TestRuntimes.Mono)] + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(true)] + [InlineData(false)] + public void CreateInstance_CollectibleAssembly(bool useDynamicCode) + { + if (PlatformDetection.IsNonBundledAssemblyLoadingSupported) + { + RemoteInvokeOptions options = new(); + if (!useDynamicCode) + { + DisableDynamicCode(options); + } + + using var remoteHandle = RemoteExecutor.Invoke(static () => + { + Assert.False(Collectible_IsAssemblyLoaded()); + Collectible_LoadAndCreate(useCollectibleAssembly : true, out WeakReference asmWeakRef, out WeakReference typeWeakRef); + + for (int i = 0; (typeWeakRef.IsAlive || asmWeakRef.IsAlive) && (i < 10); i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + // These should be GC'd. + Assert.False(asmWeakRef.IsAlive, "asmWeakRef.IsAlive"); + Assert.False(typeWeakRef.IsAlive, "typeWeakRef.IsAlive"); + Assert.False(Collectible_IsAssemblyLoaded()); + }, options); + } + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(true)] + [InlineData(false)] + public void CreateInstance_NormalAssembly(bool useDynamicCode) + { + RemoteInvokeOptions options = new(); + if (!useDynamicCode) + { + DisableDynamicCode(options); + } + + using var remoteHandle = RemoteExecutor.Invoke(static () => + { + Assert.False(Collectible_IsAssemblyLoaded()); + Collectible_LoadAndCreate(useCollectibleAssembly: false, out WeakReference asmWeakRef, out WeakReference typeWeakRef); + + for (int i = 0; (typeWeakRef.IsAlive || asmWeakRef.IsAlive) && (i < 10); i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + // These will not be GC'd. + Assert.True(asmWeakRef.IsAlive, "alcWeakRef.IsAlive"); + Assert.True(typeWeakRef.IsAlive, "typeWeakRef.IsAlive"); + Assert.True(Collectible_IsAssemblyLoaded()); + }, options); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Collectible_LoadAndCreate(bool useCollectibleAssembly, out WeakReference asmWeakRef, out WeakReference typeWeakRef) + { + Assembly asm; + object obj; + + if (useCollectibleAssembly) + { + asm = MyLoadContext.LoadAsCollectable(); + obj = CreateWithActivator(asm); + Assert.True(obj.GetType().Assembly.IsCollectible); + } + else + { + asm = MyLoadContext.LoadNormal(); + obj = CreateWithActivator(asm); + Assert.False(obj.GetType().Assembly.IsCollectible); + } + + Assert.True(Collectible_IsAssemblyLoaded()); + asmWeakRef = new WeakReference(asm); + typeWeakRef = new WeakReference(obj.GetType()); + + static object CreateWithActivator(Assembly asm) + { + Type t = asm.GetType("CollectibleAssembly.ClassToCreate"); + MethodInfo mi = t.GetMethod("Create", BindingFlags.Static | BindingFlags.Public, new Type[] { typeof(ServiceProvider) }); + + object instance; + ServiceCollection services = new(); + using (ServiceProvider provider = services.BuildServiceProvider()) + { + instance = mi.Invoke(null, new object[] { provider }); + } + + return instance; + } + } + + static bool Collectible_IsAssemblyLoaded() + { + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + for (int i = 0; i < assemblies.Length; i++) + { + Assembly asm = assemblies[i]; + string asmName = Path.GetFileName(asm.Location); + if (asmName == "CollectibleAssembly.dll") + { + return true; + } + } + + return false; + } +#endif + private static void DisableDynamicCode(RemoteInvokeOptions options) { // We probably only need to set 'IsDynamicCodeCompiled' since only that is checked, @@ -581,5 +707,36 @@ public ClassWithStringDefaultValue(string text = "DEFAULT") Text = text; } } -} +#if NETCOREAPP + internal class MyLoadContext : AssemblyLoadContext + { + private MyLoadContext() : base(isCollectible: true) + { + } + + public Assembly LoadAssembly() + { + Assembly asm = LoadFromAssemblyPath(GetPath()); + Assert.Equal(GetLoadContext(asm), this); + return asm; + } + + public static Assembly LoadAsCollectable() + { + MyLoadContext alc = new MyLoadContext(); + return alc.LoadAssembly(); + } + + public static Assembly LoadNormal() + { + return Assembly.LoadFrom(GetPath()); + } + + private static string GetPath() + { + return Path.Combine(Directory.GetCurrentDirectory(), "CollectibleAssembly.dll"); + } + } +#endif +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj index 4ac3c02d7157a3..067508506a82fe 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkMinimum) @@ -24,6 +24,7 @@ + From 267b39201599f6493b1d8f23874fbcca9e8f6c96 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:27:35 -0600 Subject: [PATCH 156/345] JIT: ensure AVX512 ternary operands aren't used twice (#91883) Don't spill unused zeros early; we might decide to use them later. Fixes #91796. Co-authored-by: Andy Ayers --- src/coreclr/jit/hwintrinsicxarch.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 488f65b5ac008d..065999982a87a9 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -3602,17 +3602,19 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); - if (unusedVal1) + // Consume operands we won't use, in case they have side effects. + // + if (unusedVal1 && !(*val1)->IsVectorZero()) { impAppendTree(gtUnusedValNode(*val1), CHECK_SPILL_ALL, impCurStmtDI); } - if (unusedVal2) + if (unusedVal2 && !(*val2)->IsVectorZero()) { impAppendTree(gtUnusedValNode(*val2), CHECK_SPILL_ALL, impCurStmtDI); } - if (unusedVal3) + if (unusedVal3 && !(*val3)->IsVectorZero()) { impAppendTree(gtUnusedValNode(*val3), CHECK_SPILL_ALL, impCurStmtDI); } From 4adb83e748513d5c69fb7be791b3940f1fe2dc07 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 08:26:55 -0700 Subject: [PATCH 157/345] [release/8.0] Fix `Item4` is missing in some `ValueTuple`s' `IStructuralEquatable.Equals` (#91470) * Add missing comparisons * Add unit tests --------- Co-authored-by: Hamish Arblaster --- .../src/System/ValueTuple.cs | 4 + .../tests/ValueTupleTests.cs | 104 ++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/ValueTuple.cs b/src/libraries/System.Private.CoreLib/src/System/ValueTuple.cs index 240ad862ffcf24..aa919ea294f78d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ValueTuple.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ValueTuple.cs @@ -1125,6 +1125,7 @@ other is ValueTuple vt && comparer.Equals(Item1, vt.Item1) && comparer.Equals(Item2, vt.Item2) && comparer.Equals(Item3, vt.Item3) && + comparer.Equals(Item4, vt.Item4) && comparer.Equals(Item5, vt.Item5); int IComparable.CompareTo(object? other) @@ -1366,6 +1367,7 @@ other is ValueTuple vt && comparer.Equals(Item1, vt.Item1) && comparer.Equals(Item2, vt.Item2) && comparer.Equals(Item3, vt.Item3) && + comparer.Equals(Item4, vt.Item4) && comparer.Equals(Item5, vt.Item5) && comparer.Equals(Item6, vt.Item6); @@ -1625,6 +1627,7 @@ other is ValueTuple vt && comparer.Equals(Item1, vt.Item1) && comparer.Equals(Item2, vt.Item2) && comparer.Equals(Item3, vt.Item3) && + comparer.Equals(Item4, vt.Item4) && comparer.Equals(Item5, vt.Item5) && comparer.Equals(Item6, vt.Item6) && comparer.Equals(Item7, vt.Item7); @@ -1908,6 +1911,7 @@ other is ValueTuple vt && comparer.Equals(Item1, vt.Item1) && comparer.Equals(Item2, vt.Item2) && comparer.Equals(Item3, vt.Item3) && + comparer.Equals(Item4, vt.Item4) && comparer.Equals(Item5, vt.Item5) && comparer.Equals(Item6, vt.Item6) && comparer.Equals(Item7, vt.Item7) && diff --git a/src/libraries/System.ValueTuple/tests/ValueTupleTests.cs b/src/libraries/System.ValueTuple/tests/ValueTupleTests.cs index 9507b31388b1f8..147b4ea9647cbf 100644 --- a/src/libraries/System.ValueTuple/tests/ValueTupleTests.cs +++ b/src/libraries/System.ValueTuple/tests/ValueTupleTests.cs @@ -799,6 +799,12 @@ public static void OneTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1).Equals(ValueTuple.Create(1))); + Assert.False(ValueTuple.Create(1).Equals(ValueTuple.Create(0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1)).Equals(ValueTuple.Create(1), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1)).Equals(ValueTuple.Create(0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1)).ToString()); var vtWithNull = new ValueTuple(null); @@ -831,6 +837,14 @@ public static void TwoTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1, 2).Equals(ValueTuple.Create(1, 2))); + Assert.False(ValueTuple.Create(1, 2).Equals(ValueTuple.Create(0, 2))); + Assert.False(ValueTuple.Create(1, 2).Equals(ValueTuple.Create(1, 0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1, 2)).Equals(ValueTuple.Create(1, 2), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2)).Equals(ValueTuple.Create(0, 2), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2)).Equals(ValueTuple.Create(1, 0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1, 2)).ToString()); var vtWithNull = new ValueTuple(null, null); @@ -866,6 +880,16 @@ public static void ThreeTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1, 2, 3).Equals(ValueTuple.Create(1, 2, 3))); + Assert.False(ValueTuple.Create(1, 2, 3).Equals(ValueTuple.Create(0, 2, 3))); + Assert.False(ValueTuple.Create(1, 2, 3).Equals(ValueTuple.Create(1, 0, 3))); + Assert.False(ValueTuple.Create(1, 2, 3).Equals(ValueTuple.Create(1, 2, 0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1, 2, 3)).Equals(ValueTuple.Create(1, 2, 3), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3)).Equals(ValueTuple.Create(0, 2, 3), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3)).Equals(ValueTuple.Create(1, 0, 3), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3)).Equals(ValueTuple.Create(1, 2, 0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2, 3)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1, 2, 3)).ToString()); var vtWithNull = new ValueTuple(null, null, null); @@ -905,6 +929,18 @@ public static void FourTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1, 2, 3, 4).Equals(ValueTuple.Create(1, 2, 3, 4))); + Assert.False(ValueTuple.Create(1, 2, 3, 4).Equals(ValueTuple.Create(0, 2, 3, 4))); + Assert.False(ValueTuple.Create(1, 2, 3, 4).Equals(ValueTuple.Create(1, 0, 3, 4))); + Assert.False(ValueTuple.Create(1, 2, 3, 4).Equals(ValueTuple.Create(1, 2, 0, 4))); + Assert.False(ValueTuple.Create(1, 2, 3, 4).Equals(ValueTuple.Create(1, 2, 3, 0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4)).Equals(ValueTuple.Create(1, 2, 3, 4), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4)).Equals(ValueTuple.Create(0, 2, 3, 4), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4)).Equals(ValueTuple.Create(1, 0, 3, 4), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4)).Equals(ValueTuple.Create(1, 2, 0, 4), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4)).Equals(ValueTuple.Create(1, 2, 3, 0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1, 2, 3, 4)).ToString()); var vtWithNull = new ValueTuple(null, null, null, null); @@ -947,6 +983,20 @@ public static void FiveTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1, 2, 3, 4, 5).Equals(ValueTuple.Create(1, 2, 3, 4, 5))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5).Equals(ValueTuple.Create(0, 2, 3, 4, 5))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5).Equals(ValueTuple.Create(1, 0, 3, 4, 5))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5).Equals(ValueTuple.Create(1, 2, 0, 4, 5))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5).Equals(ValueTuple.Create(1, 2, 3, 0, 5))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5).Equals(ValueTuple.Create(1, 2, 3, 4, 0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5)).Equals(ValueTuple.Create(1, 2, 3, 4, 5), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5)).Equals(ValueTuple.Create(0, 2, 3, 4, 5), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5)).Equals(ValueTuple.Create(1, 0, 3, 4, 5), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5)).Equals(ValueTuple.Create(1, 2, 0, 4, 5), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5)).Equals(ValueTuple.Create(1, 2, 3, 0, 5), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5)).Equals(ValueTuple.Create(1, 2, 3, 4, 0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1, 2, 3, 4, 5)).ToString()); var vtWithNull = new ValueTuple(null, null, null, null, null); @@ -992,6 +1042,22 @@ public static void SixTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 6))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(0, 2, 3, 4, 5, 6))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(1, 0, 3, 4, 5, 6))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(1, 2, 0, 4, 5, 6))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(1, 2, 3, 0, 5, 6))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(1, 2, 3, 4, 0, 6))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 6), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(0, 2, 3, 4, 5, 6), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(1, 0, 3, 4, 5, 6), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(1, 2, 0, 4, 5, 6), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(1, 2, 3, 0, 5, 6), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(1, 2, 3, 4, 0, 6), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6)).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1, 2, 3, 4, 5, 6)).ToString()); var vtWithNull = new ValueTuple(null, null, null, null, null, null); @@ -1040,6 +1106,24 @@ public static void SevenTuples() Assert.False(((IStructuralEquatable)sc).Equals(sc, DummyTestEqualityComparer.Instance)); + Assert.True(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(0, 2, 3, 4, 5, 6, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 0, 3, 4, 5, 6, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 2, 0, 4, 5, 6, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 2, 3, 0, 5, 6, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 2, 3, 4, 0, 6, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 0, 7))); + Assert.False(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 6, 0))); + + Assert.True(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 6, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(0, 2, 3, 4, 5, 6, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 0, 3, 4, 5, 6, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 2, 0, 4, 5, 6, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 2, 3, 0, 5, 6, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 2, 3, 4, 0, 6, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 0, 7), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).Equals(ValueTuple.Create(1, 2, 3, 4, 5, 6, 0), TestEqualityComparer.Instance)); + Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7)", CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(1, 2, 3, 4, 5, 6, 7)).ToString()); var vtWithNull = new ValueTuple(null, null, null, null, null, null, null); @@ -1109,6 +1193,26 @@ public static void EightTuples() Assert.False(se.Equals(t, DummyTestEqualityComparer.Instance)); + Assert.True(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(0, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 0, 3, 4, 5, 6, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 0, 4, 5, 6, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 3, 0, 5, 6, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 3, 4, 0, 6, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 3, 4, 5, 0, 7, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 3, 4, 5, 6, 0, ValueTuple.Create(8)))); + Assert.False(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)).Equals(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(0)))); + + Assert.True(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(0, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 0, 3, 4, 5, 6, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 0, 4, 5, 6, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 3, 0, 5, 6, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 3, 4, 0, 6, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 3, 4, 5, 0, 7, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 3, 4, 5, 6, 0, ValueTuple.Create(8)), TestEqualityComparer.Instance)); + Assert.False(((IStructuralEquatable)CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(8))).Equals(CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create(0)), TestEqualityComparer.Instance)); + // Notice that 0-tuple prints as empty position Assert.Equal("(1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, )", CreateLong(1, 2, 3, 4, 5, 6, 7, CreateLong(1, 2, 3, 4, 5, 6, 7, ValueTuple.Create())).ToString()); From 52ff583dbf5af1f70433c6805f5e0c697426bc52 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 08:56:53 -0700 Subject: [PATCH 158/345] Don't log warnings for certain RemoveAttributeInstances (#91866) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #88994. ILLinker attribute XML format has a way to express "only remove these attributes when parameter X has value of Y". We currently generate a warning and don't trim the attribute at all. The savings from trimming these attributes are going to be miniscule. Even in IL, this is scraping the bottom of the barrel. In Native AOT these attributes are pretty effectively deduplicated across assemblies. We'll likely never need this. This keeps the existing behavior (don't trim the attribute), but removes the warning. Co-authored-by: Michal Strehovský --- .../ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index fc0249f76847e5..45be574e031eac 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -1093,7 +1093,7 @@ private void ProcessAttribute(TypeDesc type, XPathNavigator nav) string internalValue = GetAttribute(nav, "internal"); if (!string.IsNullOrEmpty(internalValue)) { - if (!IsRemoveAttributeInstances(internalValue) || !nav.IsEmptyElement) + if (!IsRemoveAttributeInstances(internalValue)) { LogWarning(nav, DiagnosticId.UnrecognizedInternalAttribute, internalValue); } From ac388a199b8c0fda2b13022cfc4b052c5291fba9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:07:15 -0700 Subject: [PATCH 159/345] [release/8.0] JIT: Fix illegal IR created by GetElement/ToScalar lowering (#91874) * JIT: Fix illegal IR created by GetElement/ToScalar lowering These could create TYP_ULONG/TYP_UINT indirs/LCL_FLD nodes, which are illegal. Fix #91174 * Add test * Fix license header in new test --------- Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/lowerxarch.cpp | 24 +++++++-------- .../JitBlue/Runtime_91174/Runtime_91174.cs | 30 +++++++++++++++++++ .../Runtime_91174/Runtime_91174.csproj | 8 +++++ 3 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.csproj diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 00143839a440d7..d1c3e317d83b87 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -3754,17 +3754,14 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) // We want to optimize GetElement down to an Indir where possible as // this unlocks additional containment opportunities for various nodes - var_types newType; - GenTree* newBase; - GenTree* newIndex; - uint32_t newScale; - int32_t newOffset; + GenTree* newBase; + GenTree* newIndex; + uint32_t newScale; + int32_t newOffset; GenTreeIndir* indir = op1->AsIndir(); GenTree* addr = indir->Addr(); - newType = simdBaseType; - if (addr->OperIsAddrMode()) { // We have an existing addressing mode, so we want to try and @@ -3860,7 +3857,8 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) new (comp, GT_LEA) GenTreeAddrMode(addr->TypeGet(), newBase, newIndex, newScale, newOffset); BlockRange().InsertBefore(node, newAddr); - GenTreeIndir* newIndir = comp->gtNewIndir(newType, newAddr, (indir->gtFlags & GTF_IND_FLAGS)); + GenTreeIndir* newIndir = + comp->gtNewIndir(JITtype2varType(simdBaseJitType), newAddr, (indir->gtFlags & GTF_IND_FLAGS)); BlockRange().InsertBefore(node, newIndir); LIR::Use use; @@ -3911,8 +3909,8 @@ GenTree* Lowering::LowerHWIntrinsicGetElement(GenTreeHWIntrinsic* node) if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && ((lclOffs + elemSize) <= lclDsc->lvExactSize())) { - GenTree* lclFld = - comp->gtNewLclFldNode(lclVar->GetLclNum(), simdBaseType, static_cast(lclOffs)); + GenTree* lclFld = comp->gtNewLclFldNode(lclVar->GetLclNum(), JITtype2varType(simdBaseJitType), + static_cast(lclOffs)); BlockRange().InsertBefore(node, lclFld); LIR::Use use; @@ -5327,7 +5325,8 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) GenTreeIndir* indir = op1->AsIndir(); - GenTreeIndir* newIndir = comp->gtNewIndir(simdBaseType, indir->Addr(), (indir->gtFlags & GTF_IND_FLAGS)); + GenTreeIndir* newIndir = + comp->gtNewIndir(JITtype2varType(simdBaseJitType), indir->Addr(), (indir->gtFlags & GTF_IND_FLAGS)); BlockRange().InsertBefore(node, newIndir); LIR::Use use; @@ -5359,7 +5358,8 @@ GenTree* Lowering::LowerHWIntrinsicToScalar(GenTreeHWIntrinsic* node) if (lclDsc->lvDoNotEnregister && (lclOffs <= 0xFFFF) && ((lclOffs + elemSize) <= lclDsc->lvExactSize())) { - GenTree* lclFld = comp->gtNewLclFldNode(lclVar->GetLclNum(), simdBaseType, lclVar->GetLclOffs()); + GenTree* lclFld = + comp->gtNewLclFldNode(lclVar->GetLclNum(), JITtype2varType(simdBaseJitType), lclVar->GetLclOffs()); BlockRange().InsertBefore(node, lclFld); LIR::Use use; diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.cs new file mode 100644 index 00000000000000..3ae45f998542b4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public class Runtime_91174 +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static int Foo(ref Vector256 v1, ref Vector256 v2) + { + if (Vector256.ToScalar(v1) < Vector256.ToScalar(v2)) + { + Console.WriteLine("FAIL"); + return 101; + } + + return 100; + } + + [Fact] + public static int TestEntryPoint() + { + Vector256 v1 = Vector256.Create(20); + Vector256 v2 = Vector256.Create(10); + return Foo(ref v1, ref v2); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91174/Runtime_91174.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 0f3d1ed15f64cb9a9d4f47d1a1ed433e0047e16c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Sep 2023 10:22:35 -0700 Subject: [PATCH 160/345] [release/8.0] [iOS] Fix trimming warnings in HttpClientHandler.AnyMobile (#91877) * Unconditionally supress trimming warnings when calling InvokeNativeHandlerMethod * Update HttpClientHandler --------- Co-authored-by: Simon Rozsival --- ...LLink.Suppressions.Mobile.LibraryBuild.xml | 269 ------------------ .../src/System.Net.Http.csproj | 3 +- ...ntHandler.AnyMobile.InvokeNativeHandler.cs | 192 +++++++------ .../Net/Http/HttpClientHandler.AnyMobile.cs | 23 +- 4 files changed, 112 insertions(+), 375 deletions(-) delete mode 100644 src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.Mobile.LibraryBuild.xml diff --git a/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.Mobile.LibraryBuild.xml b/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.Mobile.LibraryBuild.xml deleted file mode 100644 index 7fd4d6a15a34fb..00000000000000 --- a/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.Mobile.LibraryBuild.xml +++ /dev/null @@ -1,269 +0,0 @@ - - - - - ILLink - IL2075 - member - M:System.Net.Http.HttpClientHandler.InvokeNativeHandlerMethod(System.String,System.Object[]) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetUseCookies() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetUseCookies(System.Boolean) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetCookieContainer() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetCookieContainer(System.Net.CookieContainer) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetAllowAutoRedirect() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetAllowAutoRedirect(System.Boolean) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetCredentials() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetCredentials(System.Net.ICredentials) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetAutomaticDecompression() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetAutomaticDecompression(System.Net.DecompressionMethods) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetUseProxy() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetUseProxy(System.Boolean) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetProxy() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetProxy(System.Net.IWebProxy) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetPreAuthenticate() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetPreAuthenticate(System.Boolean) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetMaxAutomaticRedirections() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetMaxAutomaticRedirections(System.Int32) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetServerCertificateCustomValidationCallback - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetServerCertificateCustomValidationCallback(System.Func{System.Net.Http.HttpRequestMessage,System.Security.Cryptography.X509Certificates.X509Certificate2,System.Security.Cryptography.X509Certificates.X509Chain,System.Net.Security.SslPolicyErrors,System.Boolean}) - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetCheckCertificateRevocationList() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetCheckCertificateRevocationList(System.Boolean) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetClientCertificateOptions() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetClientCertificateOptions(System.Net.Http.ClientCertificateOption) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetClientCertificates() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetDefaultProxyCredentials() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetDefaultProxyCredentials(System.Net.ICredentials) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetMaxConnectionsPerServer() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetMaxConnectionsPerServer(System.Int32) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetMaxResponseHeadersLength() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetMaxResponseHeadersLength(System.Int32) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetProperties() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetSupportsAutomaticDecompression() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetSupportsProxy() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetSupportsRedirectConfiguration() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.GetSslProtocols() - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - ILLink - IL2035 - member - M:System.Net.Http.HttpClientHandler.SetSslProtocols(System.Security.Authentication.SslProtocols) - The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. - - - diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index f263f9480cd67e..67909e99ba391b 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -25,7 +25,6 @@ - @@ -477,4 +476,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs index c11aa3a0c323f5..8f8c101b9e4a52 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs @@ -6,6 +6,8 @@ using System.Diagnostics.CodeAnalysis; using System.Net.Security; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; @@ -16,135 +18,130 @@ public partial class HttpClientHandler : HttpMessageHandler private static MethodInfo? _nativeHandlerMethod; #if TARGET_ANDROID - private const string NativeHandlerType = "Xamarin.Android.Net.AndroidMessageHandler"; - private const string AssemblyName = "Mono.Android"; + private const string NativeHandlerType = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android"; private const string GetHttpMessageHandlerType = "Android.Runtime.AndroidEnvironment, Mono.Android"; #elif TARGET_IOS - private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler"; - private const string AssemblyName = "Microsoft.iOS"; + private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler, Microsoft.iOS"; private const string GetHttpMessageHandlerType = "ObjCRuntime.RuntimeOptions, Microsoft.iOS"; #elif TARGET_MACCATALYST - private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler"; - private const string AssemblyName = "Microsoft.MacCatalyst"; + private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler, Microsoft.MacCatalyst"; private const string GetHttpMessageHandlerType = "ObjCRuntime.RuntimeOptions, Microsoft.MacCatalyst"; #elif TARGET_TVOS - private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler"; - private const string AssemblyName = "Microsoft.tvOS"; + private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler, Microsoft.tvOS"; private const string GetHttpMessageHandlerType = "ObjCRuntime.RuntimeOptions, Microsoft.tvOS"; #else #error Unknown target #endif - [DynamicDependency("get_DefaultProxyCredentials", NativeHandlerType, AssemblyName)] - private ICredentials? GetDefaultProxyCredentials() => (ICredentials?)InvokeNativeHandlerMethod("get_DefaultProxyCredentials"); + private ICredentials? GetDefaultProxyCredentials() + => (ICredentials?)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_DefaultProxyCredentials")!); - [DynamicDependency("set_DefaultProxyCredentials", NativeHandlerType, AssemblyName)] - private void SetDefaultProxyCredentials(ICredentials? value) => InvokeNativeHandlerMethod("set_DefaultProxyCredentials", value); + private void SetDefaultProxyCredentials(ICredentials? value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_DefaultProxyCredentials")!, value); - [DynamicDependency("get_MaxConnectionsPerServer", NativeHandlerType, AssemblyName)] - private int GetMaxConnectionsPerServer() => (int)InvokeNativeHandlerMethod("get_MaxConnectionsPerServer"); + private int GetMaxConnectionsPerServer() + => (int)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_MaxConnectionsPerServer")!); - [DynamicDependency("set_MaxConnectionsPerServer", NativeHandlerType, AssemblyName)] - private void SetMaxConnectionsPerServer(int value) => InvokeNativeHandlerMethod("set_MaxConnectionsPerServer", value); + private void SetMaxConnectionsPerServer(int value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_MaxConnectionsPerServer")!, value); - [DynamicDependency("get_MaxResponseHeadersLength", NativeHandlerType, AssemblyName)] - private int GetMaxResponseHeadersLength() => (int)InvokeNativeHandlerMethod("get_MaxResponseHeadersLength"); + private int GetMaxResponseHeadersLength() + => (int)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_MaxResponseHeadersLength")!); - [DynamicDependency("set_MaxResponseHeadersLength", NativeHandlerType, AssemblyName)] - private void SetMaxResponseHeadersLength(int value) => InvokeNativeHandlerMethod("set_MaxResponseHeadersLength", value); + private void SetMaxResponseHeadersLength(int value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_MaxResponseHeadersLength")!, value); - [DynamicDependency("get_ClientCertificateOptions", NativeHandlerType, AssemblyName)] - private ClientCertificateOption GetClientCertificateOptions() => (ClientCertificateOption)InvokeNativeHandlerMethod("get_ClientCertificateOptions"); + private ClientCertificateOption GetClientCertificateOptions() + => (ClientCertificateOption)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_ClientCertificateOptions")!); - [DynamicDependency("set_ClientCertificateOptions", NativeHandlerType, AssemblyName)] - private void SetClientCertificateOptions(ClientCertificateOption value) => InvokeNativeHandlerMethod("set_ClientCertificateOptions", value); + private void SetClientCertificateOptions(ClientCertificateOption value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_ClientCertificateOptions")!, value); - [DynamicDependency("get_ClientCertificates", NativeHandlerType, AssemblyName)] - private X509CertificateCollection GetClientCertificates() => (X509CertificateCollection)InvokeNativeHandlerMethod("get_ClientCertificates"); + private X509CertificateCollection GetClientCertificates() + => (X509CertificateCollection)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_ClientCertificates")!); - [DynamicDependency("get_ServerCertificateCustomValidationCallback", NativeHandlerType, AssemblyName)] - private Func GetServerCertificateCustomValidationCallback() => (Func)InvokeNativeHandlerMethod("get_ServerCertificateCustomValidationCallback"); + private Func GetServerCertificateCustomValidationCallback() + => (Func)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_ServerCertificateCustomValidationCallback")!); - [DynamicDependency("set_ServerCertificateCustomValidationCallback", NativeHandlerType, AssemblyName)] - private void SetServerCertificateCustomValidationCallback(Func? value) => InvokeNativeHandlerMethod("set_ServerCertificateCustomValidationCallback", value); + private void SetServerCertificateCustomValidationCallback(Func? value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_ServerCertificateCustomValidationCallback")!, value); - [DynamicDependency("get_CheckCertificateRevocationList", NativeHandlerType, AssemblyName)] - private bool GetCheckCertificateRevocationList() => (bool)InvokeNativeHandlerMethod("get_CheckCertificateRevocationList"); + private bool GetCheckCertificateRevocationList() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_CheckCertificateRevocationList")!); - [DynamicDependency("set_CheckCertificateRevocationList", NativeHandlerType, AssemblyName)] - private void SetCheckCertificateRevocationList(bool value) => InvokeNativeHandlerMethod("set_CheckCertificateRevocationList", value); + private void SetCheckCertificateRevocationList(bool value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_CheckCertificateRevocationList")!, value); - [DynamicDependency("get_SslProtocols", NativeHandlerType, AssemblyName)] - private SslProtocols GetSslProtocols() => (SslProtocols)InvokeNativeHandlerMethod("get_SslProtocols"); + private SslProtocols GetSslProtocols() + => (SslProtocols)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SslProtocols")!); - [DynamicDependency("set_SslProtocols", NativeHandlerType, AssemblyName)] - private void SetSslProtocols(SslProtocols value) => InvokeNativeHandlerMethod("set_SslProtocols", value); + private void SetSslProtocols(SslProtocols value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_SslProtocols")!, value); - [DynamicDependency("get_Properties", NativeHandlerType, AssemblyName)] - private IDictionary GetProperties() => (IDictionary)InvokeNativeHandlerMethod("get_Properties"); + private IDictionary GetProperties() + => (IDictionary)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_Properties")!); - [DynamicDependency("get_SupportsAutomaticDecompression", NativeHandlerType, AssemblyName)] - private bool GetSupportsAutomaticDecompression() => (bool)InvokeNativeHandlerMethod("get_SupportsAutomaticDecompression"); + private bool GetSupportsAutomaticDecompression() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SupportsAutomaticDecompression")!); - [DynamicDependency("get_SupportsProxy", NativeHandlerType, AssemblyName)] - private bool GetSupportsProxy() => (bool)InvokeNativeHandlerMethod("get_SupportsProxy"); + private bool GetSupportsProxy() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SupportsProxy")!); - [DynamicDependency("get_SupportsRedirectConfiguration", NativeHandlerType, AssemblyName)] - private bool GetSupportsRedirectConfiguration() => (bool)InvokeNativeHandlerMethod("get_SupportsRedirectConfiguration"); + private bool GetSupportsRedirectConfiguration() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SupportsRedirectConfiguration")!); - [DynamicDependency("get_AutomaticDecompression", NativeHandlerType, AssemblyName)] - private DecompressionMethods GetAutomaticDecompression() => (DecompressionMethods)InvokeNativeHandlerMethod("get_AutomaticDecompression"); + private DecompressionMethods GetAutomaticDecompression() + => (DecompressionMethods)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_AutomaticDecompression")!); - [DynamicDependency("set_AutomaticDecompression", NativeHandlerType, AssemblyName)] - private void SetAutomaticDecompression(DecompressionMethods value) => InvokeNativeHandlerMethod("set_AutomaticDecompression", value); + private void SetAutomaticDecompression(DecompressionMethods value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_AutomaticDecompression")!, value); - [DynamicDependency("get_UseProxy", NativeHandlerType, AssemblyName)] - private bool GetUseProxy() => (bool)InvokeNativeHandlerMethod("get_UseProxy"); + private bool GetUseProxy() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_UseProxy")!); - [DynamicDependency("set_UseProxy", NativeHandlerType, AssemblyName)] - private void SetUseProxy(bool value) => InvokeNativeHandlerMethod("set_UseProxy", value); + private void SetUseProxy(bool value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_UseProxy")!, value); - [DynamicDependency("get_Proxy", NativeHandlerType, AssemblyName)] - private IWebProxy GetProxy() => (IWebProxy)InvokeNativeHandlerMethod("get_Proxy"); + private IWebProxy GetProxy() + => (IWebProxy)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_Proxy")!); - [DynamicDependency("set_Proxy", NativeHandlerType, AssemblyName)] - private void SetProxy(IWebProxy value) => InvokeNativeHandlerMethod("set_Proxy", value); + private void SetProxy(IWebProxy value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_Proxy")!, value); - [DynamicDependency("get_PreAuthenticate", NativeHandlerType, AssemblyName)] - private bool GetPreAuthenticate() => (bool)InvokeNativeHandlerMethod("get_PreAuthenticate"); + private bool GetPreAuthenticate() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_PreAuthenticate")!); - [DynamicDependency("set_PreAuthenticate", NativeHandlerType, AssemblyName)] - private void SetPreAuthenticate(bool value) => InvokeNativeHandlerMethod("set_PreAuthenticate", value); + private void SetPreAuthenticate(bool value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_PreAuthenticate")!, value); - [DynamicDependency("get_MaxAutomaticRedirections", NativeHandlerType, AssemblyName)] - private int GetMaxAutomaticRedirections() => (int)InvokeNativeHandlerMethod("get_MaxAutomaticRedirections"); + private int GetMaxAutomaticRedirections() + => (int)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_MaxAutomaticRedirections")!); - [DynamicDependency("set_MaxAutomaticRedirections", NativeHandlerType, AssemblyName)] - private void SetMaxAutomaticRedirections(int value) => InvokeNativeHandlerMethod("set_MaxAutomaticRedirections", value); + private void SetMaxAutomaticRedirections(int value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_MaxAutomaticRedirections")!, value); - [DynamicDependency("get_UseCookies", NativeHandlerType, AssemblyName)] - private bool GetUseCookies() => (bool)InvokeNativeHandlerMethod("get_UseCookies"); + private bool GetUseCookies() => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_UseCookies")!); - [DynamicDependency("set_UseCookies", NativeHandlerType, AssemblyName)] - private void SetUseCookies(bool value) => InvokeNativeHandlerMethod("set_UseCookies", value); + private void SetUseCookies(bool value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_UseCookies")!, value); - [DynamicDependency("get_CookieContainer", NativeHandlerType, AssemblyName)] - private CookieContainer GetCookieContainer() => (CookieContainer)InvokeNativeHandlerMethod("get_CookieContainer"); + private CookieContainer GetCookieContainer() + => (CookieContainer)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_CookieContainer")!); - [DynamicDependency("set_CookieContainer", NativeHandlerType, AssemblyName)] - private void SetCookieContainer(CookieContainer value) => InvokeNativeHandlerMethod("set_CookieContainer", value); + private void SetCookieContainer(CookieContainer value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_CookieContainer")!, value); - [DynamicDependency("get_AllowAutoRedirect", NativeHandlerType, AssemblyName)] - private bool GetAllowAutoRedirect() => (bool)InvokeNativeHandlerMethod("get_AllowAutoRedirect"); + private bool GetAllowAutoRedirect() + => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_AllowAutoRedirect")!); - [DynamicDependency("set_AllowAutoRedirect", NativeHandlerType, AssemblyName)] - private void SetAllowAutoRedirect(bool value) => InvokeNativeHandlerMethod("set_AllowAutoRedirect", value); + private void SetAllowAutoRedirect(bool value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_AllowAutoRedirect")!, value); - [DynamicDependency("get_Credentials", NativeHandlerType, AssemblyName)] - private ICredentials GetCredentials() => (ICredentials)InvokeNativeHandlerMethod("get_Credentials"); + private ICredentials GetCredentials() + => (ICredentials)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_Credentials")!); - [DynamicDependency("set_Credentials", NativeHandlerType, AssemblyName)] - private void SetCredentials(ICredentials? value) => InvokeNativeHandlerMethod("set_Credentials", value); + private void SetCredentials(ICredentials? value) + => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_Credentials")!, value); private static HttpMessageHandler CreateNativeHandler() { @@ -156,5 +153,36 @@ private static HttpMessageHandler CreateNativeHandler() return (HttpMessageHandler)_nativeHandlerMethod!.Invoke(null, null)!; } + + private object InvokeNativeHandlerGetter(Func getMethod, [CallerMemberName] string? cachingKey = null) + { + return InvokeNativeHandlerMethod(getMethod, parameters: null, cachingKey!); + } + + private void InvokeNativeHandlerSetter(Func getMethod, object? value, [CallerMemberName] string? cachingKey = null) + { + InvokeNativeHandlerMethod(getMethod, parameters: new object?[] { value }, cachingKey!); + } + + private object InvokeNativeHandlerMethod(Func getMethod, object?[]? parameters, string cachingKey) + { + MethodInfo? method; + + if (!s_cachedMethods.TryGetValue(cachingKey, out method)) + { + method = getMethod(); + s_cachedMethods[cachingKey] = method; + } + + try + { + return method!.Invoke(_nativeHandler, parameters)!; + } + catch (TargetInvocationException e) + { + ExceptionDispatchInfo.Capture(e.InnerException!).Throw(); + throw; + } + } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs index d1b3db12b8ed1c..dd7d005dbc3c27 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs @@ -4,12 +4,12 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Metrics; using System.Globalization; using System.Net.Http.Metrics; using System.Net.Security; using System.Reflection; -using System.Runtime.ExceptionServices; using System.Runtime.Versioning; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; @@ -796,27 +796,6 @@ private void ThrowForModifiedManagedSslOptionsIfStarted() _socketHandler!.SslOptions = _socketHandler!.SslOptions; } - private object InvokeNativeHandlerMethod(string name, params object?[] parameters) - { - MethodInfo? method; - - if (!s_cachedMethods.TryGetValue(name, out method)) - { - method = _nativeHandler!.GetType()!.GetMethod(name); - s_cachedMethods[name] = method; - } - - try - { - return method!.Invoke(_nativeHandler, parameters)!; - } - catch (TargetInvocationException e) - { - ExceptionDispatchInfo.Capture(e.InnerException!).Throw(); - throw; - } - } - private static bool IsNativeHandlerEnabled => RuntimeSettingParser.QueryRuntimeSettingSwitch( "System.Net.Http.UseNativeHttpHandler", false); From d34a059b42a333956dfab085c8011b8d05ba5066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:46:12 -0700 Subject: [PATCH 161/345] Revert "[release/8.0] Update dependencies from dotnet/roslyn (#91482)" (#92011) This reverts commit 282da2cd568a4e1429990d3257efbc3724b79fee. --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 942050ec170f13..68a0bcba3d449d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - d080175cabfe297ebf079af099279b61913bcc28 + 3686f3061a9202260a0de4d06e91855b0fa21e8c - + https://github.com/dotnet/roslyn - d080175cabfe297ebf079af099279b61913bcc28 + 3686f3061a9202260a0de4d06e91855b0fa21e8c - + https://github.com/dotnet/roslyn - d080175cabfe297ebf079af099279b61913bcc28 + 3686f3061a9202260a0de4d06e91855b0fa21e8c https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 646f22880d530d..25577272a24e6e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23459.2 - 4.8.0-3.23459.2 - 4.8.0-3.23459.2 + 4.8.0-3.23451.1 + 4.8.0-3.23451.1 + 4.8.0-3.23451.1 diff --git a/eng/Versions.props b/eng/Versions.props index 25577272a24e6e..ab7d5680216416 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23458.2 - 1.0.0-prerelease.23458.2 - 1.0.0-prerelease.23458.2 - 1.0.0-prerelease.23458.2 - 1.0.0-prerelease.23458.2 - 1.0.0-prerelease.23458.2 + 1.0.0-prerelease.23462.6 + 1.0.0-prerelease.23462.6 + 1.0.0-prerelease.23462.6 + 1.0.0-prerelease.23462.6 + 1.0.0-prerelease.23462.6 + 1.0.0-prerelease.23462.6 16.11.27-beta1.23180.1 2.0.0-beta4.23307.1 From 6afd6964b0dfa2e1f2fb6491ff6ac8e615b7442f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 09:50:09 -0700 Subject: [PATCH 171/345] [release/8.0] Don't shut down event pipe in DLLs on Windows (#92044) Trying to enable EventSourceSupport in a shared library project on Native AOT currently results in a build failure since this is actively blocked in the targets. But EventSourceSupport/event pipe mostly work, with some issues (#91762). The blocking makes it impossible for anyone to run diagnostics on their shared library. This is a regression from .NET 7, where it was at least possible to get GC ETW events in PerfView on Windows. This changes the blocking to a suppressible warning, and fixes and issue that was causing a shutdown hang. --- src/coreclr/nativeaot/Bootstrap/main.cpp | 10 +++++++-- .../Microsoft.NETCore.Native.Publish.targets | 3 +-- src/coreclr/nativeaot/Runtime/startup.cpp | 22 ++++++++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index cc78cf8d6710a9..c2ff85b50e81fd 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -93,7 +93,7 @@ static char& __unbox_z = __stop___unbox; #endif // _MSC_VER -extern "C" bool RhInitialize(); +extern "C" bool RhInitialize(bool isDll); extern "C" void RhSetRuntimeInitializationCallback(int (*fPtr)()); extern "C" bool RhRegisterOSModule(void * pModule, @@ -164,7 +164,13 @@ extern "C" void __managed__Startup(); static int InitializeRuntime() { - if (!RhInitialize()) + if (!RhInitialize( +#ifdef NATIVEAOT_DLL + /* isDll */ true +#else + /* isDll */ false +#endif + )) return -1; void * osModule = PalGetModuleHandleFromPointer((void*)&NATIVEAOT_ENTRYPOINT); diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets index 32eefb307eb0fd..caee0777b30ddd 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets @@ -50,8 +50,7 @@ Text="RuntimeIdentifier is required for native compilation. Try running dotnet publish with the -r option value specified." /> - - + diff --git a/src/coreclr/nativeaot/Runtime/startup.cpp b/src/coreclr/nativeaot/Runtime/startup.cpp index 32cbab53cb8304..5db04aa27766dd 100644 --- a/src/coreclr/nativeaot/Runtime/startup.cpp +++ b/src/coreclr/nativeaot/Runtime/startup.cpp @@ -297,6 +297,10 @@ static void UninitDLL() Thread* g_threadPerformingShutdown = NULL; #endif +#if defined(_WIN32) && defined(FEATURE_PERFTRACING) +bool g_safeToShutdownTracing; +#endif + static void __cdecl OnProcessExit() { #ifdef _WIN32 @@ -309,8 +313,16 @@ static void __cdecl OnProcessExit() #endif #ifdef FEATURE_PERFTRACING - EventPipe_Shutdown(); - DiagnosticServer_Shutdown(); +#ifdef _WIN32 + // We forgo shutting down event pipe if it wouldn't be safe and could lead to a hang. + // If there was an active trace session, the trace will likely be corrupted without + // orderly shutdown. See https://github.com/dotnet/runtime/issues/89346. + if (g_safeToShutdownTracing) +#endif + { + EventPipe_Shutdown(); + DiagnosticServer_Shutdown(); + } #endif } @@ -348,7 +360,7 @@ void RuntimeThreadShutdown(void* thread) #endif } -extern "C" bool RhInitialize() +extern "C" bool RhInitialize(bool isDll) { if (!PalInit()) return false; @@ -357,6 +369,10 @@ extern "C" bool RhInitialize() atexit(&OnProcessExit); #endif +#if defined(_WIN32) && defined(FEATURE_PERFTRACING) + g_safeToShutdownTracing = !isDll; +#endif + if (!InitDLL(PalGetModuleHandleFromPointer((void*)&RhInitialize))) return false; From 18ac00889e96961119db0b72fe1532d2299d292a Mon Sep 17 00:00:00 2001 From: Nikola Milosavljevic Date: Thu, 14 Sep 2023 10:39:41 -0700 Subject: [PATCH 172/345] Update THIRD-PARTY-NOTICES for 8.0 release (#91933) * Update THIRD-PARTY-NOTICES for 8.0 release * Addressed review comments * Remove test-only notice --- THIRD-PARTY-NOTICES.TXT | 8 +- src/installer/pkg/THIRD-PARTY-NOTICES.TXT | 343 +++++++++++++++++++++- 2 files changed, 345 insertions(+), 6 deletions(-) diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT index 53855810b5af9f..4b40333f72ce4f 100644 --- a/THIRD-PARTY-NOTICES.TXT +++ b/THIRD-PARTY-NOTICES.TXT @@ -480,8 +480,8 @@ Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment Corporation makes any representations about the suitability of this software for any purpose." -License notice for The LLVM Compiler Infrastructure ---------------------------------------------------- +License notice for The LLVM Compiler Infrastructure (Legacy License) +-------------------------------------------------------------------- Developed by: @@ -986,8 +986,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -License for remote stack unwind (https://github.com/llvm/llvm-project/blob/main/lldb/source/Symbol/CompactUnwindInfo.cpp) --------------------------------------- +License notice for The LLVM Project +----------------------------------- Copyright 2019 LLVM Project diff --git a/src/installer/pkg/THIRD-PARTY-NOTICES.TXT b/src/installer/pkg/THIRD-PARTY-NOTICES.TXT index fcb519506d511e..237af34f098f15 100644 --- a/src/installer/pkg/THIRD-PARTY-NOTICES.TXT +++ b/src/installer/pkg/THIRD-PARTY-NOTICES.TXT @@ -449,8 +449,8 @@ Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment Corporation makes any representations about the suitability of this software for any purpose." -License notice for The LLVM Compiler Infrastructure ---------------------------------------------------- +License notice for The LLVM Compiler Infrastructure (Legacy License) +-------------------------------------------------------------------- Developed by: @@ -1481,3 +1481,342 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +Copyright (c) 2015, Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +License for C# Implementation of Fast CRC Computation +----------------------------------------------------- + +https://github.com/SixLabors/ImageSharp/blob/f4f689ce67ecbcc35cebddba5aacb603e6d1068a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs + +Copyright (c) Six Labors. +Licensed under the Apache License, Version 2.0. + +Available at +https://github.com/SixLabors/ImageSharp/blob/f4f689ce67ecbcc35cebddba5aacb603e6d1068a/LICENSE + +License for Fast CRC Computation +-------------------------------------- + +https://github.com/intel/isa-l/blob/33a2d9484595c2d6516c920ce39a694c144ddf69/crc/crc32_ieee_by4.asm +https://github.com/intel/isa-l/blob/33a2d9484595c2d6516c920ce39a694c144ddf69/crc/crc64_ecma_norm_by8.asm + +Copyright(c) 2011-2015 Intel Corporation All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License for fastmod (https://github.com/lemire/fastmod), ibm-fpgen (https://github.com/nigeltao/parse-number-fxx-test-data) and fastrange (https://github.com/lemire/fastrange) +-------------------------------------- + + Copyright 2018 Daniel Lemire + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +License for Jb Evain +--------------------- + +Copyright (c) 2006 Jb Evain (jbevain@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. + +License for MurmurHash3 +-------------------------------------- + +https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp + +MurmurHash3 was written by Austin Appleby, and is placed in the public +domain. The author hereby disclaims copyright to this source + +License notice for The LLVM Project +----------------------------------- + +Copyright 2019 LLVM Project + +Licensed under the Apache License, Version 2.0 (the "License") with LLVM Exceptions; +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://llvm.org/LICENSE.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +License for sse4-strstr (https://github.com/WojciechMula/sse4-strstr) +-------------------------------------- + + Copyright (c) 2008-2016, Wojciech Mula + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License for the Teddy multi-substring searching implementation +-------------------------------------- + +https://github.com/BurntSushi/aho-corasick + +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +License notice for amd/aocl-libm-ose +------------------------------- + +Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +License notice for code from The Practice of Programming +------------------------------- + +Copyright (C) 1999 Lucent Technologies + +Excerpted from 'The Practice of Programming +by Brian W. Kernighan and Rob Pike + +You may use this code for any purpose, as long as you leave the copyright notice and book citation attached. + +License notice for fmtlib/fmt +------------------------------- + +Formatting library for C++ + +Copyright (c) 2012 - present, Victor Zverovich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for gRPC +=================================== + +Copyright 2019 The gRPC Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +License notice for m-ou-se/floatconv +------------------------------- + +Copyright (c) 2020 Mara Bos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for MsQuic +-------------------------------------- + +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. + +Available at +https://github.com/microsoft/msquic/blob/main/LICENSE + +License notice for vectorized hex parsing +-------------------------------------------------------- + +Copyright (c) 2022, Geoff Langdale +Copyright (c) 2022, Wojciech Mula +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Notice for Euclidean Affine Functions and Applications to Calendar +Algorithms +------------------------------- + +Aspects of Date/Time processing based on algorithm described in "Euclidean Affine Functions and Applications to Calendar +Algorithms", Cassio Neri and Lorenz Schneider. https://arxiv.org/pdf/2102.06959.pdf From 3aec9611c87bd4ec3432123a1e598d8eccee0c4d Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Thu, 14 Sep 2023 10:44:58 -0700 Subject: [PATCH 173/345] [release/8.0] Metrics Feature Switch (#92019) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Metrics Feature Switch * Add missed empty lines --------- Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- docs/workflow/trimming/feature-switches.md | 1 + .../ILLink/ILLink.Substitutions.Shared.xml | 10 ++++ ...System.Diagnostics.DiagnosticSource.csproj | 4 ++ .../System/Diagnostics/Metrics/Instrument.cs | 6 ++ .../src/System/Diagnostics/Metrics/Meter.cs | 10 ++++ .../Diagnostics/Metrics/MeterListener.cs | 32 ++++++++++- ....Diagnostics.DiagnosticSource.Tests.csproj | 1 + .../tests/TestNotSupported.cs | 56 +++++++++++++++++++ 8 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/ILLink/ILLink.Substitutions.Shared.xml create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/tests/TestNotSupported.cs diff --git a/docs/workflow/trimming/feature-switches.md b/docs/workflow/trimming/feature-switches.md index 7fa3045547e0f0..635187684116b5 100644 --- a/docs/workflow/trimming/feature-switches.md +++ b/docs/workflow/trimming/feature-switches.md @@ -13,6 +13,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif | EnableUnsafeBinaryFormatterSerialization | System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization | BinaryFormatter serialization support is trimmed when set to false | | EventSourceSupport | System.Diagnostics.Tracing.EventSource.IsSupported | Any EventSource related code or logic is trimmed when set to false | | InvariantGlobalization | System.Globalization.Invariant | All globalization specific code and data is trimmed when set to true | +| MetricsSupport | System.Diagnostics.Metrics.Meter.IsSupported | Any Metrics related code or logic is trimmed when set to false | | PredefinedCulturesOnly | System.Globalization.PredefinedCulturesOnly | Don't allow creating a culture for which the platform does not have data | | HybridGlobalization | System.Globalization.Hybrid | Properties connected with the mixed: platform-specific + icu-based globalization will be trimmed | | UseSystemResourceKeys | System.Resources.UseSystemResourceKeys | Any localizable resources for system assemblies is trimmed when set to true | diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/ILLink/ILLink.Substitutions.Shared.xml b/src/libraries/System.Diagnostics.DiagnosticSource/src/ILLink/ILLink.Substitutions.Shared.xml new file mode 100644 index 00000000000000..b67ac8623c402a --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/ILLink/ILLink.Substitutions.Shared.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 24a23478b7c0c2..49b7834a9de36c 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -20,6 +20,10 @@ System.Diagnostics.DiagnosticSource true + + + + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs index 0cb50f523f0282..c1e2fcb199b3a5 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Instrument.cs @@ -64,6 +64,12 @@ protected Instrument(Meter meter, string name, string? unit, string? description /// protected void Publish() { + // All instruments call Publish when they are created. We don't want to publish the instrument if the Meter is not supported. + if (!Meter.IsSupported) + { + return; + } + List? allListeners = null; lock (Instrument.SyncObject) { diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs index a5722aa7b6c4dc..60314b1d5b4c00 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs @@ -17,6 +17,11 @@ public class Meter : IDisposable private Dictionary> _nonObservableInstrumentsCache = new(); internal bool Disposed { get; private set; } + internal static bool IsSupported { get; } = InitializeIsSupported(); + + private static bool InitializeIsSupported() => + AppContext.TryGetSwitch("System.Diagnostics.Metrics.Meter.IsSupported", out bool isSupported) ? isSupported : true; + /// /// Initialize a new instance of the Meter using the . /// @@ -77,6 +82,11 @@ private void Initialize(string name, string? version, IEnumerable - /// A delegate to represent the Meterlistener callbacks used in measurements recording operation. + /// A delegate to represent the MeterListener callbacks used in measurements recording operation. /// public delegate void MeasurementCallback(Instrument instrument, T measurement, ReadOnlySpan> tags, object? state) where T : struct; @@ -56,6 +56,11 @@ public MeterListener() { } /// A state object which will be passed back to the callback getting measurements events. public void EnableMeasurementEvents(Instrument instrument, object? state = null) { + if (!Meter.IsSupported) + { + return; + } + bool oldStateStored = false; bool enabled = false; object? oldState = null; @@ -92,6 +97,11 @@ public void EnableMeasurementEvents(Instrument instrument, object? state = null) /// The state object originally passed to method. public object? DisableMeasurementEvents(Instrument instrument) { + if (!Meter.IsSupported) + { + return default; + } + object? state = null; lock (Instrument.SyncObject) { @@ -114,6 +124,11 @@ public void EnableMeasurementEvents(Instrument instrument, object? state = null) /// The callback which can be used to get measurement recording of numeric type T. public void SetMeasurementEventCallback(MeasurementCallback? measurementCallback) where T : struct { + if (!Meter.IsSupported) + { + return; + } + measurementCallback ??= (instrument, measurement, tags, state) => { /* no-op */}; if (typeof(T) == typeof(byte)) @@ -155,6 +170,11 @@ public void SetMeasurementEventCallback(MeasurementCallback? measurementCa /// public void Start() { + if (!Meter.IsSupported) + { + return; + } + List? publishedInstruments = null; lock (Instrument.SyncObject) { @@ -184,6 +204,11 @@ public void Start() /// public void RecordObservableInstruments() { + if (!Meter.IsSupported) + { + return; + } + List? exceptionsList = null; DiagNode? current = _enabledMeasurementInstruments.First; while (current is not null) @@ -215,6 +240,11 @@ public void RecordObservableInstruments() /// public void Dispose() { + if (!Meter.IsSupported) + { + return; + } + Dictionary? callbacksArguments = null; Action? measurementsCompleted = MeasurementsCompleted; diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 7e8136e0a1a6b9..29a8e55dc2fc02 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/TestNotSupported.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TestNotSupported.cs new file mode 100644 index 00000000000000..43fae749957204 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/TestNotSupported.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.DotNet.RemoteExecutor; +using System.Diagnostics.Metrics; +using Xunit; + +namespace System.Diagnostics.Metrics.Tests +{ + public class MetricsNotSupportedTest + { + /// + /// Tests using Metrics when the System.Diagnostics.Metrics.Meter.IsSupported + /// feature switch is set to disable all metrics operations. + /// + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(false)] + [InlineData(true)] + public void IsSupportedSwitch(bool value) + { + RemoteInvokeOptions options = new RemoteInvokeOptions(); + options.RuntimeConfigurationOptions.Add("System.Diagnostics.Metrics.Meter.IsSupported", value); + + RemoteExecutor.Invoke((val) => + { + bool isSupported = bool.Parse(val); + + Meter meter = new Meter("IsSupportedTest"); + Counter counter = meter.CreateCounter("counter"); + bool instrumentsPublished = false; + bool instrumentCompleted = false; + long counterValue = 100; + + using (MeterListener listener = new MeterListener + { + InstrumentPublished = (instruments, theListener) => instrumentsPublished = true, + MeasurementsCompleted = (instruments, state) => instrumentCompleted = true + }) + { + listener.EnableMeasurementEvents(counter, null); + listener.SetMeasurementEventCallback((inst, measurement, tags, state) => counterValue = measurement); + listener.Start(); + + Assert.Equal(isSupported, counter.Enabled); + + counter.Add(20); + } + meter.Dispose(); + + Assert.Equal(isSupported, instrumentsPublished); + Assert.Equal(isSupported, instrumentCompleted); + Assert.Equal(isSupported ? 20 : 100, counterValue); + }, value.ToString(), options).Dispose(); + } + } +} From 1978fc2974bdeb0b08c114b61b3d423cef42269f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:45:18 -0700 Subject: [PATCH 174/345] [release/8.0] Arm64: Pass the small size accurately to emitIns_valid_imm_for_ldst_offset (#92041) * Pass the right size to check if immediate will fit or not * Revert "Pass the right size to check if immediate will fit or not" This reverts commit d7c511abce6634d65434a149e719c6f4516d6966. * review feedback * fix the size to be passed to the instruction * fix the assert --------- Co-authored-by: Kunal Pathak --- src/coreclr/jit/codegenarm64.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index f99602d21d953b..d937cd67747e25 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -327,19 +327,38 @@ bool CodeGen::genInstrWithConstant(instruction ins, break; case INS_strb: + assert(size == EA_1BYTE); + immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, EA_1BYTE); + break; + case INS_strh: + assert(size == EA_2BYTE); + immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, EA_2BYTE); + break; + case INS_str: // reg1 is a source register for store instructions assert(tmpReg != reg1); // regTmp can not match any source register immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, size); break; + case INS_ldrb: case INS_ldrsb: + immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, EA_1BYTE); + break; + + case INS_ldrh: case INS_ldrsh: + immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, EA_2BYTE); + break; + case INS_ldrsw: - case INS_ldrb: - case INS_ldrh: + assert(size == EA_4BYTE); + immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, EA_4BYTE); + break; + case INS_ldr: + assert((size == EA_4BYTE) || (size == EA_8BYTE) || (size == EA_16BYTE)); immFitsInIns = emitter::emitIns_valid_imm_for_ldst_offset(imm, size); break; From 5c02390cfbbb0befd4b2e3a18f099ef3bfad7da6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:47:04 -0700 Subject: [PATCH 175/345] [release/8.0] Fix si.ibAllocated in FrozenObjectHeapManager (#92052) * Fix si.ibAllocated in FrozenObjectHeapManager * Add an assert --------- Co-authored-by: EgorBo --- src/coreclr/vm/frozenobjectheap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/frozenobjectheap.cpp b/src/coreclr/vm/frozenobjectheap.cpp index 41af231816a645..8f11f3c8c74d64 100644 --- a/src/coreclr/vm/frozenobjectheap.cpp +++ b/src/coreclr/vm/frozenobjectheap.cpp @@ -180,10 +180,12 @@ void FrozenObjectSegment::RegisterOrUpdate(uint8_t* current, size_t sizeCommited segment_info si; si.pvMem = m_pStart; si.ibFirstObject = sizeof(ObjHeader); - si.ibAllocated = (size_t)current; + si.ibAllocated = (size_t)current - (size_t)si.pvMem; si.ibCommit = sizeCommited; si.ibReserved = m_Size; + assert((size_t)current >= (size_t)si.pvMem); + // NOTE: RegisterFrozenSegment may take a GC lock inside. m_SegmentHandle = GCHeapUtilities::GetGCHeap()->RegisterFrozenSegment(&si); if (m_SegmentHandle == nullptr) From b77984825befe46b8ce240ed7fde5bc13e8d574b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:49:06 -0700 Subject: [PATCH 176/345] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230913.3 (#92059) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23462.6 -> To Version 1.0.0-prerelease.23463.3 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f49cc41ea7ab7e..a58805b364fe5f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 4665b3d04e1da3796b965c3c3e3b97f55c449a6e - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - fdf994eebae397c96184fa78dcf488c220ae0082 + 61240e7f115581d0c6f04db60242e8eae1de1496 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - fdf994eebae397c96184fa78dcf488c220ae0082 + 61240e7f115581d0c6f04db60242e8eae1de1496 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - fdf994eebae397c96184fa78dcf488c220ae0082 + 61240e7f115581d0c6f04db60242e8eae1de1496 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - fdf994eebae397c96184fa78dcf488c220ae0082 + 61240e7f115581d0c6f04db60242e8eae1de1496 https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - fdf994eebae397c96184fa78dcf488c220ae0082 + 61240e7f115581d0c6f04db60242e8eae1de1496 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - fdf994eebae397c96184fa78dcf488c220ae0082 + 61240e7f115581d0c6f04db60242e8eae1de1496 diff --git a/eng/Versions.props b/eng/Versions.props index b055d7591ccd01..e7972b2a592d27 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23462.6 - 1.0.0-prerelease.23462.6 - 1.0.0-prerelease.23462.6 - 1.0.0-prerelease.23462.6 - 1.0.0-prerelease.23462.6 - 1.0.0-prerelease.23462.6 + 1.0.0-prerelease.23463.3 + 1.0.0-prerelease.23463.3 + 1.0.0-prerelease.23463.3 + 1.0.0-prerelease.23463.3 + 1.0.0-prerelease.23463.3 + 1.0.0-prerelease.23463.3 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 From 0189dc443da58b45e4df96f90e17c23ace9e1b79 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 10:49:25 -0700 Subject: [PATCH 177/345] [wasi] Work arounbd WASI's mmap implementation not returning aligned memory. (#92061) Some code in sgen like sgen_los_free_object () expects the return address to be aligned. Hopefully fixes https://github.com/dotnet/runtime/issues/88501 and others. Co-authored-by: Zoltan Varga --- src/mono/mono/utils/mono-mmap-wasm.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/utils/mono-mmap-wasm.c b/src/mono/mono/utils/mono-mmap-wasm.c index 5c38aac9f36641..b2f417b0860385 100644 --- a/src/mono/mono/utils/mono-mmap-wasm.c +++ b/src/mono/mono/utils/mono-mmap-wasm.c @@ -90,8 +90,8 @@ mono_setmmapjit (int flag) /* Ignored on HOST_WASM */ } -void* -mono_valloc (void *addr, size_t size, int flags, MonoMemAccountType type) +static void* +valloc_impl (void *addr, size_t size, int flags, MonoMemAccountType type) { void *ptr; int mflags = 0; @@ -119,6 +119,19 @@ mono_valloc (void *addr, size_t size, int flags, MonoMemAccountType type) return ptr; } +void* +mono_valloc (void *addr, size_t size, int flags, MonoMemAccountType type) +{ +#if HOST_WASI + // WASI implements mmap using malloc, so the returned address is not page aligned + // and our code depends on it + g_assert (!addr); + return mono_valloc_aligned (size, mono_pagesize (), flags, type); +#else + return valloc_impl (addr, size, flags, type); +#endif +} + static GHashTable *valloc_hash; typedef struct { @@ -130,7 +143,7 @@ void* mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type) { /* Allocate twice the memory to be able to put the block on an aligned address */ - char *mem = (char *) mono_valloc (NULL, size + alignment, flags, type); + char *mem = (char *) valloc_impl (NULL, size + alignment, flags, type); char *aligned; if (!mem) From 851a9362c53b565e87bb3ddb49a07d7709be4d66 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Thu, 14 Sep 2023 23:13:43 +0400 Subject: [PATCH 178/345] Do not throw PNSE exception from NegotiateAuthentication constructor, report Unsupported status instead (#91753) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- .../FunctionalTests/NtAuthTests.FakeServer.cs | 27 +++++++++++++++++++ .../Net/NegotiateAuthenticationPal.Managed.cs | 21 ++++++++++----- .../Net/NegotiateAuthenticationPal.Unix.cs | 18 ++++++------- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs index 780db637ba335e..c29beca16f4015 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/NtAuthTests.FakeServer.cs @@ -139,5 +139,32 @@ await server.AcceptConnectionAsync(async connection => }).ConfigureAwait(false); }); } + + [Fact] + [SkipOnPlatform(TestPlatforms.Browser | TestPlatforms.Windows, "DefaultCredentials are unsupported for NTLM on Unix / Managed implementation")] + public async Task DefaultHandler_FakeServer_DefaultCredentials() + { + await LoopbackServer.CreateClientAndServerAsync( + async uri => + { + HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, uri); + requestMessage.Version = new Version(1, 1); + HttpMessageHandler handler = new HttpClientHandler() { Credentials = CredentialCache.DefaultCredentials }; + using (var client = new HttpClient(handler)) + { + HttpResponseMessage response = await client.SendAsync(requestMessage); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + }, + async server => + { + await server.AcceptConnectionAsync(async connection => + { + var authHeader = "WWW-Authenticate: NTLM\r\n"; + await connection.SendResponseAsync(HttpStatusCode.Unauthorized, authHeader).ConfigureAwait(false); + connection.CompleteRequestProcessing(); + }).ConfigureAwait(false); + }); + } } } diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Managed.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Managed.cs index 4e5e8906b795cc..fff331646b73c6 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Managed.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Managed.cs @@ -9,16 +9,23 @@ internal abstract partial class NegotiateAuthenticationPal { public static NegotiateAuthenticationPal Create(NegotiateAuthenticationClientOptions clientOptions) { - switch (clientOptions.Package) + try { - case NegotiationInfoClass.NTLM: - return new ManagedNtlmNegotiateAuthenticationPal(clientOptions); + switch (clientOptions.Package) + { + case NegotiationInfoClass.NTLM: + return new ManagedNtlmNegotiateAuthenticationPal(clientOptions); - case NegotiationInfoClass.Negotiate: - return new ManagedSpnegoNegotiateAuthenticationPal(clientOptions); + case NegotiationInfoClass.Negotiate: + return new ManagedSpnegoNegotiateAuthenticationPal(clientOptions); - default: - return new UnsupportedNegotiateAuthenticationPal(clientOptions); + default: + return new UnsupportedNegotiateAuthenticationPal(clientOptions); + } + } + catch (PlatformNotSupportedException) + { + return new UnsupportedNegotiateAuthenticationPal(clientOptions); } } diff --git a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs index 900d66c05bfc7a..ed1fe4e2e91937 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs @@ -23,20 +23,20 @@ internal partial class NegotiateAuthenticationPal public static NegotiateAuthenticationPal Create(NegotiateAuthenticationClientOptions clientOptions) { - if (UseManagedNtlm) + try { - switch (clientOptions.Package) + if (UseManagedNtlm) { - case NegotiationInfoClass.NTLM: - return new ManagedNtlmNegotiateAuthenticationPal(clientOptions); + switch (clientOptions.Package) + { + case NegotiationInfoClass.NTLM: + return new ManagedNtlmNegotiateAuthenticationPal(clientOptions); - case NegotiationInfoClass.Negotiate: - return new ManagedSpnegoNegotiateAuthenticationPal(clientOptions, supportKerberos: true); + case NegotiationInfoClass.Negotiate: + return new ManagedSpnegoNegotiateAuthenticationPal(clientOptions, supportKerberos: true); + } } - } - try - { return new UnixNegotiateAuthenticationPal(clientOptions); } catch (Win32Exception) From dbcde1d274e0cda97b3470368becb05e42195f4e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 12:21:43 -0700 Subject: [PATCH 179/345] [release/8.0] Update dependencies from dotnet/roslyn (#91913) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies from https://github.com/dotnet/roslyn build 20230911.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23461.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230911.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23461.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.9 * Update dependencies from https://github.com/dotnet/roslyn build 20230912.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23459.2 -> To Version 4.8.0-3.23462.10 * Permit TypeAttributes.BeforeFieldInit for InterfaceTypeTestBase --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> Co-authored-by: Eric StJohn --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- .../tests/System/Type/TypePropertyTests.cs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a58805b364fe5f..8521a5487a5fec 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 3686f3061a9202260a0de4d06e91855b0fa21e8c + 1b7a6f807cb8ce709048debae6b771f4705a697a - + https://github.com/dotnet/roslyn - 3686f3061a9202260a0de4d06e91855b0fa21e8c + 1b7a6f807cb8ce709048debae6b771f4705a697a - + https://github.com/dotnet/roslyn - 3686f3061a9202260a0de4d06e91855b0fa21e8c + 1b7a6f807cb8ce709048debae6b771f4705a697a https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index e7972b2a592d27..f437ad1a604c22 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23451.1 - 4.8.0-3.23451.1 - 4.8.0-3.23451.1 + 4.8.0-3.23462.10 + 4.8.0-3.23462.10 + 4.8.0-3.23462.10 8.0.100-preview.7.23329.3 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 2.5.1-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 - 8.0.0-beta.23451.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 2.5.1-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 + 8.0.0-beta.23463.1 6.0.0-preview.1.102 @@ -184,7 +184,7 @@ 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 - 8.0.0-alpha.0.23455.2 + 8.0.0-alpha.0.23461.1 2.4.2 1.0.0 2.4.5 @@ -213,7 +213,7 @@ 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23454.2 + 0.11.4-alpha.23461.1 8.0.0-rc.1.23406.6 @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.2.23460.1 + 8.0.0-rc.2.23463.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda diff --git a/global.json b/global.json index 6d208cff376c28..2b41b42c3256e6 100644 --- a/global.json +++ b/global.json @@ -8,9 +8,9 @@ "dotnet": "8.0.100-preview.7.23376.3" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23451.1", - "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23451.1", - "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23451.1", + "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23463.1", + "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.23463.1", + "Microsoft.DotNet.SharedFramework.Sdk": "8.0.0-beta.23463.1", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.NET.Sdk.IL": "8.0.0-rc.1.23406.6" From dbd788512921d7d05d33d71c5a03375357c5efb8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:19:27 -0700 Subject: [PATCH 181/345] [release/8.0] Remove implicit narrowing conversions from zlib (#91962) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make zlib compile clean against MSVC C4244 and clang implicit-int-conversion Descriptions of each changes are in the respective .patch files. * Unbreak mono build --------- Co-authored-by: Levi Broderick Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- src/mono/CMakeLists.txt | 3 + ...ib-intel-compile-clean-against-C4244.patch | 75 +++++++++++++++++++ ...ake-zlib-compile-clean-against-C4244.patch | 57 ++++++++++++++ src/native/external/zlib-intel-version.txt | 2 + src/native/external/zlib-intel.cmake | 6 -- src/native/external/zlib-intel/deflate.c | 8 +- src/native/external/zlib-intel/slide_sse.c | 2 +- src/native/external/zlib-intel/trees.c | 2 +- src/native/external/zlib-version.txt | 2 + src/native/external/zlib.cmake | 6 -- src/native/external/zlib/deflate.c | 8 +- src/native/external/zlib/trees.c | 2 +- 12 files changed, 150 insertions(+), 23 deletions(-) create mode 100644 src/native/external/patches/zlib-intel/0001-Make-zlib-intel-compile-clean-against-C4244.patch create mode 100644 src/native/external/patches/zlib/0001-Make-zlib-compile-clean-against-C4244.patch diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index a57cc52b0b110b..05766210ea6be5 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -15,6 +15,9 @@ if (MSVC) if(EXISTS ${CLR_SOURCELINK_FILE_PATH}) add_link_options("/sourcelink:${CLR_SOURCELINK_FILE_PATH}") endif() + + # FIXME: Remove the line below when https://github.com/dotnet/runtime/issues/91249 is fixed. + add_compile_options($<$:/wd4244>) # conversion from 'type1' to 'type2', possible loss of data endif(MSVC) set(CROSS_ROOTFS $ENV{ROOTFS_DIR}) diff --git a/src/native/external/patches/zlib-intel/0001-Make-zlib-intel-compile-clean-against-C4244.patch b/src/native/external/patches/zlib-intel/0001-Make-zlib-intel-compile-clean-against-C4244.patch new file mode 100644 index 00000000000000..1ecb02be92ec05 --- /dev/null +++ b/src/native/external/patches/zlib-intel/0001-Make-zlib-intel-compile-clean-against-C4244.patch @@ -0,0 +1,75 @@ +From edabaf799fd071a328e0adb743a98628df6649f0 Mon Sep 17 00:00:00 2001 +From: Levi Broderick +Date: Mon, 28 Aug 2023 15:26:38 -0700 +Subject: [PATCH] Make zlib-intel compile clean against C4244 clang equivalent + is "implicit-int-conversion" warning + +The change to deflate.c is legal because 'len' has an upper bound of +MAX_STORED, which means it fits cleanly into a 16-bit integer. So +writing out 2x 8-bit values will not result in data loss. + +The change to trees.c is legal because within this loop, 'count' is +intended to have an upper bound of 138, with the target assignment +only executing if 'count' is bounded by 4. Neither the 'count' local +in isolation nor the addition that's part of the target line is +expected to result in integer overflow. But even if it did, that's a +matter for a different warning code and doesn't impact the correctness +of the narrowing cast being considered here. + +The change to slide_sse.c is legal because 'w_size' is limited to +1 << 15 (see deflateInit2_ in deflate.c), so this fits cleanly into +a 16-bit value. +--- + src/native/external/zlib-intel/deflate.c | 8 ++++---- + src/native/external/zlib-intel/slide_sse.c | 2 +- + src/native/external/zlib-intel/trees.c | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/native/external/zlib-intel/deflate.c b/src/native/external/zlib-intel/deflate.c +index bd5e95774a6..108b1a187af 100644 +--- a/src/native/external/zlib-intel/deflate.c ++++ b/src/native/external/zlib-intel/deflate.c +@@ -1553,10 +1553,10 @@ local block_state deflate_stored(s, flush) + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ +- s->pending_buf[s->pending - 4] = len; +- s->pending_buf[s->pending - 3] = len >> 8; +- s->pending_buf[s->pending - 2] = ~len; +- s->pending_buf[s->pending - 1] = ~len >> 8; ++ s->pending_buf[s->pending - 4] = (Bytef)len; ++ s->pending_buf[s->pending - 3] = (Bytef)(len >> 8); ++ s->pending_buf[s->pending - 2] = (Bytef)~len; ++ s->pending_buf[s->pending - 1] = (Bytef)(~len >> 8); + + /* Write the stored block header bytes. */ + flush_pending(s->strm); +diff --git a/src/native/external/zlib-intel/slide_sse.c b/src/native/external/zlib-intel/slide_sse.c +index 342fd562dd1..eb74202c5a0 100644 +--- a/src/native/external/zlib-intel/slide_sse.c ++++ b/src/native/external/zlib-intel/slide_sse.c +@@ -18,7 +18,7 @@ void slide_hash_sse(deflate_state *s) + unsigned n; + Posf *p; + uInt wsize = s->w_size; +- z_const __m128i xmm_wsize = _mm_set1_epi16(s->w_size); ++ z_const __m128i xmm_wsize = _mm_set1_epi16((short)s->w_size); + + n = s->hash_size; + p = &s->head[n] - 8; +diff --git a/src/native/external/zlib-intel/trees.c b/src/native/external/zlib-intel/trees.c +index 35462a1313a..f78b7d8c63e 100644 +--- a/src/native/external/zlib-intel/trees.c ++++ b/src/native/external/zlib-intel/trees.c +@@ -717,7 +717,7 @@ local void scan_tree(s, tree, max_code) + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { +- s->bl_tree[curlen].Freq += count; ++ s->bl_tree[curlen].Freq += (ush)count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; +-- +2.42.0.windows.1 + diff --git a/src/native/external/patches/zlib/0001-Make-zlib-compile-clean-against-C4244.patch b/src/native/external/patches/zlib/0001-Make-zlib-compile-clean-against-C4244.patch new file mode 100644 index 00000000000000..c2a26b3202b196 --- /dev/null +++ b/src/native/external/patches/zlib/0001-Make-zlib-compile-clean-against-C4244.patch @@ -0,0 +1,57 @@ +From 86d96652ddd60f61dc7b0c94b601f6d156d34632 Mon Sep 17 00:00:00 2001 +From: Levi Broderick +Date: Mon, 28 Aug 2023 15:26:38 -0700 +Subject: [PATCH] Make zlib compile clean against C4244 clang equivalent is + "implicit-int-conversion" warning + +The change to deflate.c is legal because 'len' has an upper bound of +MAX_STORED, which means it fits cleanly into a 16-bit integer. So +writing out 2x 8-bit values will not result in data loss. + +The change to trees.c is legal because within this loop, 'count' is +intended to have an upper bound of 138, with the target assignment +only executing if 'count' is bounded by 4. Neither the 'count' local +in isolation nor the addition that's part of the target line is +expected to result in integer overflow. But even if it did, that's a +matter for a different warning code and doesn't impact the correctness +of the narrowing cast being considered here. +--- + src/native/external/zlib/deflate.c | 8 ++++---- + src/native/external/zlib/trees.c | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/native/external/zlib/deflate.c b/src/native/external/zlib/deflate.c +index d2e1106ef5d..b7636639754 100644 +--- a/src/native/external/zlib/deflate.c ++++ b/src/native/external/zlib/deflate.c +@@ -1738,10 +1738,10 @@ local block_state deflate_stored(s, flush) + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ +- s->pending_buf[s->pending - 4] = len; +- s->pending_buf[s->pending - 3] = len >> 8; +- s->pending_buf[s->pending - 2] = ~len; +- s->pending_buf[s->pending - 1] = ~len >> 8; ++ s->pending_buf[s->pending - 4] = (Bytef)len; ++ s->pending_buf[s->pending - 3] = (Bytef)(len >> 8); ++ s->pending_buf[s->pending - 2] = (Bytef)~len; ++ s->pending_buf[s->pending - 1] = (Bytef)(~len >> 8); + + /* Write the stored block header bytes. */ + flush_pending(s->strm); +diff --git a/src/native/external/zlib/trees.c b/src/native/external/zlib/trees.c +index 5f305c47221..8a3eec559e5 100644 +--- a/src/native/external/zlib/trees.c ++++ b/src/native/external/zlib/trees.c +@@ -721,7 +721,7 @@ local void scan_tree(s, tree, max_code) + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { +- s->bl_tree[curlen].Freq += count; ++ s->bl_tree[curlen].Freq += (ush)count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; +-- +2.42.0.windows.1 + diff --git a/src/native/external/zlib-intel-version.txt b/src/native/external/zlib-intel-version.txt index d406ffbcc459b3..287c9e92512bf1 100644 --- a/src/native/external/zlib-intel-version.txt +++ b/src/native/external/zlib-intel-version.txt @@ -12,3 +12,5 @@ copied into our repo in order to build. Since then, we've just updated only those files in-place, ignoring other files in the intel/zlib repo. If new files are introduced which are necessary for building the product, feel free to bring those down as well. + +We have also applied the custom patches under the patches/zlib-intel folder. diff --git a/src/native/external/zlib-intel.cmake b/src/native/external/zlib-intel.cmake index 1b6fa0cb4765bf..e8f198271d865b 100644 --- a/src/native/external/zlib-intel.cmake +++ b/src/native/external/zlib-intel.cmake @@ -1,9 +1,3 @@ -if(MSVC) - add_compile_options($<$:/wd4244>) # conversion from 'type1' to 'type2', possible loss of data -else(CMAKE_C_COMPILER_ID MATCHES "Clang") - add_compile_options($<$:-Wno-implicit-int-conversion>) -endif() - set(ZLIB_SOURCES_BASE adler32.c compress.c diff --git a/src/native/external/zlib-intel/deflate.c b/src/native/external/zlib-intel/deflate.c index bd5e95774a689a..108b1a187af4d3 100644 --- a/src/native/external/zlib-intel/deflate.c +++ b/src/native/external/zlib-intel/deflate.c @@ -1553,10 +1553,10 @@ local block_state deflate_stored(s, flush) _tr_stored_block(s, (char *)0, 0L, last); /* Replace the lengths in the dummy stored block with len. */ - s->pending_buf[s->pending - 4] = len; - s->pending_buf[s->pending - 3] = len >> 8; - s->pending_buf[s->pending - 2] = ~len; - s->pending_buf[s->pending - 1] = ~len >> 8; + s->pending_buf[s->pending - 4] = (Bytef)len; + s->pending_buf[s->pending - 3] = (Bytef)(len >> 8); + s->pending_buf[s->pending - 2] = (Bytef)~len; + s->pending_buf[s->pending - 1] = (Bytef)(~len >> 8); /* Write the stored block header bytes. */ flush_pending(s->strm); diff --git a/src/native/external/zlib-intel/slide_sse.c b/src/native/external/zlib-intel/slide_sse.c index 342fd562dd1152..eb74202c5a04a8 100644 --- a/src/native/external/zlib-intel/slide_sse.c +++ b/src/native/external/zlib-intel/slide_sse.c @@ -18,7 +18,7 @@ void slide_hash_sse(deflate_state *s) unsigned n; Posf *p; uInt wsize = s->w_size; - z_const __m128i xmm_wsize = _mm_set1_epi16(s->w_size); + z_const __m128i xmm_wsize = _mm_set1_epi16((short)s->w_size); n = s->hash_size; p = &s->head[n] - 8; diff --git a/src/native/external/zlib-intel/trees.c b/src/native/external/zlib-intel/trees.c index 35462a1313aa83..f78b7d8c63eaed 100644 --- a/src/native/external/zlib-intel/trees.c +++ b/src/native/external/zlib-intel/trees.c @@ -717,7 +717,7 @@ local void scan_tree(s, tree, max_code) if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; + s->bl_tree[curlen].Freq += (ush)count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; diff --git a/src/native/external/zlib-version.txt b/src/native/external/zlib-version.txt index 00ce7fdbb2cd32..fcac66cc4645f4 100644 --- a/src/native/external/zlib-version.txt +++ b/src/native/external/zlib-version.txt @@ -13,3 +13,5 @@ We have also cherry-picked into our local copy: This patch only affects memLevel 9 compression. .NET doesn't currently use this memLevel, but we'll take this patch out of an abundance of caution just in case we enable this functionality in a future release. + +We have also applied the custom patches under the patches/zlib folder. diff --git a/src/native/external/zlib.cmake b/src/native/external/zlib.cmake index 862e10118cd72c..730bfc4bd14020 100644 --- a/src/native/external/zlib.cmake +++ b/src/native/external/zlib.cmake @@ -1,9 +1,3 @@ -if(MSVC) - add_compile_options($<$:/wd4244>) # conversion from 'type1' to 'type2', possible loss of data -else(CMAKE_C_COMPILER_ID MATCHES "Clang") - add_compile_options($<$:-Wno-implicit-int-conversion>) -endif() - set(ZLIB_SOURCES_BASE adler32.c compress.c diff --git a/src/native/external/zlib/deflate.c b/src/native/external/zlib/deflate.c index d2e1106ef5d07d..b763663975458c 100644 --- a/src/native/external/zlib/deflate.c +++ b/src/native/external/zlib/deflate.c @@ -1738,10 +1738,10 @@ local block_state deflate_stored(s, flush) _tr_stored_block(s, (char *)0, 0L, last); /* Replace the lengths in the dummy stored block with len. */ - s->pending_buf[s->pending - 4] = len; - s->pending_buf[s->pending - 3] = len >> 8; - s->pending_buf[s->pending - 2] = ~len; - s->pending_buf[s->pending - 1] = ~len >> 8; + s->pending_buf[s->pending - 4] = (Bytef)len; + s->pending_buf[s->pending - 3] = (Bytef)(len >> 8); + s->pending_buf[s->pending - 2] = (Bytef)~len; + s->pending_buf[s->pending - 1] = (Bytef)(~len >> 8); /* Write the stored block header bytes. */ flush_pending(s->strm); diff --git a/src/native/external/zlib/trees.c b/src/native/external/zlib/trees.c index 5f305c47221e90..8a3eec559e55bc 100644 --- a/src/native/external/zlib/trees.c +++ b/src/native/external/zlib/trees.c @@ -721,7 +721,7 @@ local void scan_tree(s, tree, max_code) if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; + s->bl_tree[curlen].Freq += (ush)count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; From 5de5c460b8cc2ab05c1d93c6514d57a30ffda889 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:20:31 -0700 Subject: [PATCH 182/345] [release/8.0] Replace http.error.reason with OTel standard error.type (#91996) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * implement standard semantics for the request.duration error tag * delete unused using * reduce s_statusCodeStrings size --------- Co-authored-by: antonfirsov Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> Co-authored-by: Anton Firszov --- .../System/Net/Http/Metrics/MetricsHandler.cs | 77 ++++++++++++------- .../tests/FunctionalTests/MetricsTest.cs | 47 ++++++++--- 2 files changed, 85 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs index 3c34e43011938e..1f353f167150e5 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs @@ -112,11 +112,12 @@ private void RequestStop(HttpRequestMessage request, HttpResponseMessage? respon tags.Add("http.response.status_code", GetBoxedStatusCode((int)response.StatusCode)); tags.Add("network.protocol.version", GetProtocolVersionString(response.Version)); } - else + + if (TryGetErrorType(response, exception, out string? errorType)) { - Debug.Assert(exception is not null); - tags.Add("http.error.reason", GetErrorReason(exception)); + tags.Add("error.type", errorType); } + TimeSpan durationTime = Stopwatch.GetElapsedTime(startTimestamp, Stopwatch.GetTimestamp()); HttpMetricsEnrichmentContext? enrichmentContext = HttpMetricsEnrichmentContext.GetEnrichmentContextForRequest(request); @@ -130,37 +131,47 @@ private void RequestStop(HttpRequestMessage request, HttpResponseMessage? respon } } - private static string GetErrorReason(Exception exception) + private static bool TryGetErrorType(HttpResponseMessage? response, Exception? exception, out string? errorType) { - if (exception is HttpRequestException e) + if (response is not null) { - Debug.Assert(Enum.GetValues().Length == 12, "We need to extend the mapping in case new values are added to HttpRequestError."); + int statusCode = (int)response.StatusCode; - string? errorReason = e.HttpRequestError switch + // In case the status code indicates a client or a server error, return the string representation of the status code. + // See the paragraph Status and the definition of 'error.type' in + // https://github.com/open-telemetry/semantic-conventions/blob/2bad9afad58fbd6b33cc683d1ad1f006e35e4a5d/docs/http/http-spans.md + if (statusCode >= 400 && statusCode <= 599) { - HttpRequestError.NameResolutionError => "name_resolution_error", - HttpRequestError.ConnectionError => "connection_error", - HttpRequestError.SecureConnectionError => "secure_connection_error", - HttpRequestError.HttpProtocolError => "http_protocol_error", - HttpRequestError.ExtendedConnectNotSupported => "extended_connect_not_supported", - HttpRequestError.VersionNegotiationError => "version_negotiation_error", - HttpRequestError.UserAuthenticationError => "user_authentication_error", - HttpRequestError.ProxyTunnelError => "proxy_tunnel_error", - HttpRequestError.InvalidResponse => "invalid_response", - HttpRequestError.ResponseEnded => "response_ended", - HttpRequestError.ConfigurationLimitExceeded => "configuration_limit_exceeded", - - // Fall back to the exception type name (including for HttpRequestError.Unknown). - _ => null - }; - - if (errorReason is not null) - { - return errorReason; + errorType = GetErrorStatusCodeString(statusCode); + return true; } } - return exception.GetType().Name; + if (exception is null) + { + errorType = null; + return false; + } + + Debug.Assert(Enum.GetValues().Length == 12, "We need to extend the mapping in case new values are added to HttpRequestError."); + errorType = (exception as HttpRequestException)?.HttpRequestError switch + { + HttpRequestError.NameResolutionError => "name_resolution_error", + HttpRequestError.ConnectionError => "connection_error", + HttpRequestError.SecureConnectionError => "secure_connection_error", + HttpRequestError.HttpProtocolError => "http_protocol_error", + HttpRequestError.ExtendedConnectNotSupported => "extended_connect_not_supported", + HttpRequestError.VersionNegotiationError => "version_negotiation_error", + HttpRequestError.UserAuthenticationError => "user_authentication_error", + HttpRequestError.ProxyTunnelError => "proxy_tunnel_error", + HttpRequestError.InvalidResponse => "invalid_response", + HttpRequestError.ResponseEnded => "response_ended", + HttpRequestError.ConfigurationLimitExceeded => "configuration_limit_exceeded", + + // Fall back to the exception type name in case of HttpRequestError.Unknown or when exception is not an HttpRequestException. + _ => exception.GetType().Name + }; + return true; } private static string GetProtocolVersionString(Version httpVersion) => (httpVersion.Major, httpVersion.Minor) switch @@ -199,6 +210,7 @@ private static TagList InitializeCommonTags(HttpRequestMessage request) } private static object[]? s_boxedStatusCodes; + private static string[]? s_statusCodeStrings; private static object GetBoxedStatusCode(int statusCode) { @@ -209,6 +221,17 @@ private static object GetBoxedStatusCode(int statusCode) : statusCode; } + private static string GetErrorStatusCodeString(int statusCode) + { + Debug.Assert(statusCode >= 400 && statusCode <= 599); + + string[] strings = LazyInitializer.EnsureInitialized(ref s_statusCodeStrings, static () => new string[200]); + int index = statusCode - 400; + return (uint)index < (uint)strings.Length + ? strings[index] ??= statusCode.ToString() + : statusCode.ToString(); + } + private sealed class SharedMeter : Meter { public static Meter Instance { get; } = new SharedMeter(); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs index da36366246f415..15bb4bcbe2bb97 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs @@ -75,8 +75,8 @@ protected static void VerifyRequestDuration(Measurement measurement, Version? protocolVersion = null, int? statusCode = null, string method = "GET", - string[] acceptedErrorReasons = null) => - VerifyRequestDuration(InstrumentNames.RequestDuration, measurement.Value, measurement.Tags.ToArray(), uri, protocolVersion, statusCode, method, acceptedErrorReasons); + string[] acceptedErrorTypes = null) => + VerifyRequestDuration(InstrumentNames.RequestDuration, measurement.Value, measurement.Tags.ToArray(), uri, protocolVersion, statusCode, method, acceptedErrorTypes); protected static void VerifyRequestDuration(string instrumentName, double measurement, @@ -85,7 +85,7 @@ protected static void VerifyRequestDuration(string instrumentName, Version? protocolVersion, int? statusCode, string method = "GET", - string[] acceptedErrorReasons = null) + string[] acceptedErrorTypes = null) { Assert.Equal(InstrumentNames.RequestDuration, instrumentName); Assert.InRange(measurement, double.Epsilon, 60); @@ -93,14 +93,14 @@ protected static void VerifyRequestDuration(string instrumentName, VerifyTag(tags, "http.request.method", method); VerifyTag(tags, "network.protocol.version", GetVersionString(protocolVersion)); VerifyTag(tags, "http.response.status_code", statusCode); - if (acceptedErrorReasons == null) + if (acceptedErrorTypes == null) { - Assert.DoesNotContain(tags, t => t.Key == "http.error.reason"); + Assert.DoesNotContain(tags, t => t.Key == "error.type"); } else { - string errorReason = (string)tags.Single(t => t.Key == "http.error.reason").Value; - Assert.Contains(errorReason, acceptedErrorReasons); + string errorReason = (string)tags.Single(t => t.Key == "error.type").Value; + Assert.Contains(errorReason, acceptedErrorTypes); } } @@ -659,7 +659,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => : [nameof(TaskCanceledException), nameof(OperationCanceledException)]; Measurement m = Assert.Single(recorder.GetMeasurements()); - VerifyRequestDuration(m, uri, acceptedErrorReasons: expectedExceptionTypes); + VerifyRequestDuration(m, uri, acceptedErrorTypes: expectedExceptionTypes); clientCompleted.SetResult(); }, @@ -703,7 +703,7 @@ public async Task RequestDuration_ConnectionError_LogsExpectedErrorReason() _output.WriteLine($"Client exception: {ex}"); Measurement m = Assert.Single(recorder.GetMeasurements()); - VerifyRequestDuration(m, uri, acceptedErrorReasons: ["connection_error"]); + VerifyRequestDuration(m, uri, acceptedErrorTypes: ["connection_error"]); } protected override void Dispose(bool disposing) @@ -793,6 +793,29 @@ await Assert.ThrowsAsync(async () => }, content: "x")); } + [Theory] + [InlineData(400)] + [InlineData(404)] + [InlineData(599)] + public Task RequestDuration_ErrorStatus_ErrorTypeRecorded(int statusCode) + { + return LoopbackServerFactory.CreateClientAndServerAsync(async uri => + { + using HttpMessageInvoker client = CreateHttpMessageInvoker(); + using InstrumentRecorder recorder = SetupInstrumentRecorder(InstrumentNames.RequestDuration); + using HttpRequestMessage request = new(HttpMethod.Get, uri) { Version = UseVersion }; + + using HttpResponseMessage response = await SendAsync(client, request); + + Measurement m = Assert.Single(recorder.GetMeasurements()); + VerifyRequestDuration(m, uri, UseVersion, statusCode, "GET", acceptedErrorTypes: new[] { $"{statusCode}" }); + + }, async server => + { + await server.AcceptConnectionSendResponseAndCloseAsync(statusCode: (HttpStatusCode)statusCode); + }); + } + [Fact] [SkipOnPlatform(TestPlatforms.Browser, "Browser is relaxed about validating HTTP headers")] public async Task RequestDuration_ConnectionClosedWhileReceivingHeaders_Recorded() @@ -814,7 +837,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => Assert.True(ex is HttpRequestException or TaskCanceledException); Measurement m = Assert.Single(recorder.GetMeasurements()); - VerifyRequestDuration(m, uri, acceptedErrorReasons: [nameof(TaskCanceledException), "response_ended"]); + VerifyRequestDuration(m, uri, acceptedErrorTypes: [nameof(TaskCanceledException), "response_ended"]); }, async server => { try @@ -869,7 +892,7 @@ await server.AcceptConnectionAsync(async connection => { await Assert.ThrowsAsync(() => clientTask); Measurement m = Assert.Single(recorder.GetMeasurements()); - VerifyRequestDuration(m, server.Address, acceptedErrorReasons: ["response_ended"]); + VerifyRequestDuration(m, server.Address, acceptedErrorTypes: ["response_ended"]); } else { @@ -967,7 +990,7 @@ await Assert.ThrowsAsync(async () => }); Measurement m = Assert.Single(recorder.GetMeasurements()); - VerifyRequestDuration(m, server.Address, acceptedErrorReasons: ["http_protocol_error"]); + VerifyRequestDuration(m, server.Address, acceptedErrorTypes: ["http_protocol_error"]); } } From 1d60c690e4ae64a4467357d4676fd5b9b3675ac8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 14:58:50 -0700 Subject: [PATCH 183/345] [release/8.0] Fix binder gen compile issues due to inaccessible members and identifier name clashes (#91967) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix binder gen compile issues due to inaccessible members and identifier name clashes * Minimize net diff of binder-gen visibility/identifier-clash fix * Improve identifier formatting * Use built-in API for accessiblity check --------- Co-authored-by: Layomi Akinrinade Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- .../src/SourceGenerators/TypeModelHelper.cs | 36 ++++ .../ConfigurationBindingGenerator.Parser.cs | 19 +- .../Helpers/Emitter/ConfigurationBinder.cs | 3 +- .../gen/Helpers/Emitter/CoreBindingHelpers.cs | 2 +- .../gen/Helpers/Emitter/Helpers.cs | 13 +- .../gen/Helpers/Parser/Extensions.cs | 62 +++++++ ...nfiguration.Binder.SourceGeneration.csproj | 2 + .../gen/Model/KnownTypeSymbols.cs | 4 + .../gen/Model/TypeSpec.cs | 10 +- .../gen/Resources/Strings.resx | 2 +- .../gen/Resources/xlf/Strings.cs.xlf | 4 +- .../gen/Resources/xlf/Strings.de.xlf | 4 +- .../gen/Resources/xlf/Strings.es.xlf | 4 +- .../gen/Resources/xlf/Strings.fr.xlf | 4 +- .../gen/Resources/xlf/Strings.it.xlf | 4 +- .../gen/Resources/xlf/Strings.ja.xlf | 4 +- .../gen/Resources/xlf/Strings.ko.xlf | 4 +- .../gen/Resources/xlf/Strings.pl.xlf | 4 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 4 +- .../gen/Resources/xlf/Strings.ru.xlf | 4 +- .../gen/Resources/xlf/Strings.tr.xlf | 4 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 4 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 4 +- .../tests/Common/ConfigurationBinderTests.cs | 2 +- .../Baselines/EmptyConfigType.generated.txt | 104 +++++++++++ .../ConfigurationBinderTests.Generator.cs | 166 ++++++++++++++++++ .../gen/Helpers/RoslynExtensions.cs | 22 --- .../gen/JsonSourceGenerator.Parser.cs | 8 +- .../System.Text.Json.SourceGeneration.targets | 1 + 29 files changed, 421 insertions(+), 87 deletions(-) create mode 100644 src/libraries/Common/src/SourceGenerators/TypeModelHelper.cs create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt diff --git a/src/libraries/Common/src/SourceGenerators/TypeModelHelper.cs b/src/libraries/Common/src/SourceGenerators/TypeModelHelper.cs new file mode 100644 index 00000000000000..73c19d61ca1225 --- /dev/null +++ b/src/libraries/Common/src/SourceGenerators/TypeModelHelper.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; +using System.Collections.Generic; + +namespace SourceGenerators +{ + internal static class TypeModelHelper + { + public static List? GetAllTypeArgumentsInScope(this INamedTypeSymbol type) + { + if (!type.IsGenericType) + { + return null; + } + + List? args = null; + TraverseContainingTypes(type); + return args; + + void TraverseContainingTypes(INamedTypeSymbol current) + { + if (current.ContainingType is INamedTypeSymbol parent) + { + TraverseContainingTypes(parent); + } + + if (!current.TypeArguments.IsEmpty) + { + (args ??= new()).AddRange(current.TypeArguments); + } + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 64db4eb58b1f77..deb0f4c0aabc0d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -9,6 +9,7 @@ using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -66,10 +67,11 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm return _sourceGenSpec; } - private static bool IsValidRootConfigType(ITypeSymbol? type) + private bool IsValidRootConfigType(ITypeSymbol? type) { if (type is null || type.SpecialType is SpecialType.System_Object or SpecialType.System_Void || + !_typeSymbols.Compilation.IsSymbolAccessibleWithin(type, _typeSymbols.Compilation.Assembly) || type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || type.IsRefLikeType || ContainsGenericParameters(type)) @@ -914,19 +916,4 @@ private void RegisterTypeDiagnostic(ITypeSymbol causingType, InvocationDiagnosti } } } - - public static class ParserExtensions - { - public static void RegisterCacheEntry(this Dictionary cache, TKey key, TEntry entry) - where TKey : notnull - where TValue : ICollection, new() - { - if (!cache.TryGetValue(key, out TValue? entryCollection)) - { - cache[key] = entryCollection = new TValue(); - } - - entryCollection.Add(entry); - } - } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs index c7ead12d65589d..c420097d99d6ae 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -138,7 +139,7 @@ void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParam EmitBlankLineIfRequired(); _writer.WriteLine($"/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively."); EmitInterceptsLocationAnnotations(interceptorInfoList); - EmitStartBlock($"public static void {Identifier.Bind}_{type.DisplayString.ToIdentifierSubstring()}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})"); + EmitStartBlock($"public static void {Identifier.Bind}_{type.IdentifierCompatibleSubstring}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})"); if (type.NeedsMemberBinding) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs index bb2bd7ac61d15a..089095aa472d5b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs @@ -923,7 +923,7 @@ private static string GetConditionKindExpr(ref bool isFirstType) } private static string GetConfigKeyCacheFieldName(ObjectSpec type) => - $"s_configKeys_{type.DisplayString.ToIdentifierSubstring()}"; + $"s_configKeys_{type.IdentifierCompatibleSubstring}"; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index 60ce9f681e077f..fe59e46f73fc0b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -245,18 +245,7 @@ private bool EmitInitException(TypeSpec type) private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}"; private static string GetInitalizeMethodDisplayString(ObjectSpec type) => - $"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayString.ToIdentifierSubstring()}"; + $"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.IdentifierCompatibleSubstring}"; } } - - internal static class EmitterExtensions - { - public static string ToIdentifierSubstring(this string typeDisplayName) => - typeDisplayName - .Replace("[]", nameof(Array)) - .Replace(", ", string.Empty) - .Replace(".", string.Empty) - .Replace("<", string.Empty) - .Replace(">", string.Empty); - } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs new file mode 100644 index 00000000000000..0ac57e88ed9ee5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis; +using SourceGenerators; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + internal static class ParserExtensions + { + private static readonly SymbolDisplayFormat s_identifierCompatibleFormat = new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, + genericsOptions: SymbolDisplayGenericsOptions.None, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + + public static void RegisterCacheEntry(this Dictionary cache, TKey key, TEntry entry) + where TKey : notnull + where TValue : ICollection, new() + { + if (!cache.TryGetValue(key, out TValue? entryCollection)) + { + cache[key] = entryCollection = new TValue(); + } + + entryCollection.Add(entry); + } + + public static string ToIdentifierCompatibleSubstring(this ITypeSymbol type) + { + if (type is IArrayTypeSymbol arrayType) + { + int rank = arrayType.Rank; + string suffix = rank == 1 ? "Array" : $"Array{rank}D"; // Array, Array2D, Array3D, ... + return ToIdentifierCompatibleSubstring(arrayType.ElementType) + suffix; + } + + string displayString = type.ContainingType is null + ? type.Name + : type.ToDisplayString(s_identifierCompatibleFormat).Replace(".", string.Empty); + + if (type is not INamedTypeSymbol { IsGenericType: true } namedType) + { + return displayString; + } + + StringBuilder sb = new(displayString); + + if (namedType.GetAllTypeArgumentsInScope() is List typeArgsInScope) + { + foreach (ITypeSymbol genericArg in typeArgsInScope) + { + sb.Append(ToIdentifierCompatibleSubstring(genericArg)); + } + } + + return sb.ToString(); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index 5b10a6f8e06c6b..f63ddec1f4b72e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -25,6 +25,7 @@ + @@ -40,6 +41,7 @@ + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs index e3a4f67ed396b4..e381dc9c7c43ee 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs @@ -13,6 +13,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal sealed record KnownTypeSymbols { + public CSharpCompilation Compilation { get; } + public INamedTypeSymbol String { get; } public INamedTypeSymbol? CultureInfo { get; } public INamedTypeSymbol? DateOnly { get; } @@ -57,6 +59,8 @@ internal sealed record KnownTypeSymbols public KnownTypeSymbols(CSharpCompilation compilation) { + Compilation = compilation; + // Primitives (needed because they are Microsoft.CodeAnalysis.SpecialType.None) CultureInfo = compilation.GetBestTypeByMetadataName(typeof(CultureInfo)); DateOnly = compilation.GetBestTypeByMetadataName("System.DateOnly"); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs index 6f5e26bf3f6d38..cf03e58e5231b1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs @@ -15,17 +15,19 @@ internal abstract record TypeSpec public TypeSpec(ITypeSymbol type) { - IsValueType = type.IsValueType; Namespace = type.ContainingNamespace?.ToDisplayString(); DisplayString = type.ToDisplayString(s_minimalDisplayFormat); - Name = Namespace + "." + DisplayString.Replace(".", "+"); - IsInterface = type.TypeKind is TypeKind.Interface; + Name = (Namespace is null ? string.Empty : Namespace + ".") + DisplayString.Replace(".", "+"); + IdentifierCompatibleSubstring = type.ToIdentifierCompatibleSubstring(); + IsValueType = type.IsValueType; } public string Name { get; } public string DisplayString { get; } + public string IdentifierCompatibleSubstring { get; } + public string? Namespace { get; } public bool IsValueType { get; } @@ -42,8 +44,6 @@ public TypeSpec(ITypeSymbol type) public virtual TypeSpec EffectiveType => this; - public bool IsInterface { get; } - protected bool CanInitComplexObject() => InitializationStrategy is not InitializationStrategy.None && InitExceptionMessage is null; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx index 3978cbaac6ce48..be66da59c6b5a7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/Strings.resx @@ -121,7 +121,7 @@ The collection type is not supported: '{0}'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. The target type for a binder call could not be determined diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf index 8c264bc592c9c0..3bc09d74a32702 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - Pro volání vazače se nevygenerovala logika vazby. Nepodporované vstupní vzory zahrnují obecná volání a předávání zabalených objektů. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Pro volání vazače se nevygenerovala logika vazby. Nepodporované vstupní vzory zahrnují obecná volání a předávání zabalených objektů. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf index 37100d25efae20..4ef47bf55a3fb4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - Für einen Binderaufruf wurde keine Bindungslogik generiert. Nicht unterstützte Eingabemuster umfassen generische Aufrufe und übergeben geschachtelte Objekte. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Für einen Binderaufruf wurde keine Bindungslogik generiert. Nicht unterstützte Eingabemuster umfassen generische Aufrufe und übergeben geschachtelte Objekte. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf index 00bf90592cc311..f74c0d799d2a5d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - No se generó la lógica de enlace para una llamada de enlazador. Los patrones de entrada no admitidos incluyen llamadas genéricas y pasar objetos en cuadros. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + No se generó la lógica de enlace para una llamada de enlazador. Los patrones de entrada no admitidos incluyen llamadas genéricas y pasar objetos en cuadros. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf index 847bc6155aaaee..739f6a85c79492 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - La logique de liaison n’a pas été générée pour un appel de classeur. Les modèles d’entrée non pris en charge incluent les appels génériques et les objets boxed de passage. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + La logique de liaison n’a pas été générée pour un appel de classeur. Les modèles d’entrée non pris en charge incluent les appels génériques et les objets boxed de passage. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf index 9ee871268cff5a..16a25f5fef4a88 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - La logica di binding non è stata generata per una chiamata binder. I modelli di input non supportati includono chiamate generiche e il passaggio di oggetti in caselle. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + La logica di binding non è stata generata per una chiamata binder. I modelli di input non supportati includono chiamate generiche e il passaggio di oggetti in caselle. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf index b7d5becee73ca2..260aa898a04f16 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - バインダー呼び出しのバインド ロジックが生成されませんでした。サポートされていない入力パターンとしては、ジェネリック呼び出し、ボックス化されたオブジェクトの受け渡しなどがあります。 + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + バインダー呼び出しのバインド ロジックが生成されませんでした。サポートされていない入力パターンとしては、ジェネリック呼び出し、ボックス化されたオブジェクトの受け渡しなどがあります。 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf index 4c94c55903310e..5b73d60a47d613 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - 바인더 호출에 대한 바인딩 논리가 생성되지 않았습니다. 지원되지 않는 입력 패턴에는 제네릭 호출 및 boxed 개체 전달이 포함됩니다. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + 바인더 호출에 대한 바인딩 논리가 생성되지 않았습니다. 지원되지 않는 입력 패턴에는 제네릭 호출 및 boxed 개체 전달이 포함됩니다. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf index 808afa9723f55a..8a675ed3e3fa03 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - Nie wygenerowano logiki powiązania dla wywołania integratora. Nieobsługiwane wzorce wejściowe obejmują wywołania ogólne i przekazywanie obiektów w ramce. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Nie wygenerowano logiki powiązania dla wywołania integratora. Nieobsługiwane wzorce wejściowe obejmują wywołania ogólne i przekazywanie obiektów w ramce. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf index 9f723e7e6af48b..5f54f60e4c13cc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - A lógica de associação não foi gerada para uma chamada de associador. Os padrões de entrada sem suporte incluem chamadas genéricas e passagem de objetos em caixa. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + A lógica de associação não foi gerada para uma chamada de associador. Os padrões de entrada sem suporte incluem chamadas genéricas e passagem de objetos em caixa. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf index cc2f61c6e9d514..bf40ee5af2c390 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - Логика привязки не была создана для вызова модуля привязки. К неподдерживаемым шаблонам ввода относятся универсальные вызовы и передача упакованных объектов. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Логика привязки не была создана для вызова модуля привязки. К неподдерживаемым шаблонам ввода относятся универсальные вызовы и передача упакованных объектов. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf index 06aaaded5cf2c1..732554a8893005 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - Bir bağlayıcı çağrısı için bağlama mantığı oluşturulmadı. Desteklenmeyen giriş desenleri genel çağrılar ve geçici kutulu nesneler içeriyor. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Bir bağlayıcı çağrısı için bağlama mantığı oluşturulmadı. Desteklenmeyen giriş desenleri genel çağrılar ve geçici kutulu nesneler içeriyor. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf index ef3affe4e22bcc..f35cf502782512 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - 未为联编程序调用生成绑定逻辑。不支持的输入模式包括泛型调用和传递装箱对象。 + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + 未为联编程序调用生成绑定逻辑。不支持的输入模式包括泛型调用和传递装箱对象。 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf index 39dd659d8890dd..ff843029507c1f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -8,8 +8,8 @@ - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls and passing boxed objects. - 未產生文件夾呼叫的繫結邏輯。不支援的輸入模式包括一般呼叫和傳遞方塊物件。 + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + 未產生文件夾呼叫的繫結邏輯。不支援的輸入模式包括一般呼叫和傳遞方塊物件。 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index a7e0474028172b..3846145f71486a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -30,7 +30,7 @@ public ConfigurationBinderTestsBase() } } - public sealed partial class ConfigurationBinderTests : ConfigurationBinderTestsBase + public partial class ConfigurationBinderTests : ConfigurationBinderTestsBase { [Fact] public void BindWithNestedTypesWithReadOnlyProperties() diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt new file mode 100644 index 00000000000000..c3db7a0ff408a5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt @@ -0,0 +1,104 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 12, 23)] + public static void Bind_TypeWithNoMembers(this IConfiguration configuration, object? instance) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 15, 23)] + public static void Bind_TypeWithNoMembers_Wrapper(this IConfiguration configuration, object? instance) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + if (instance is null) + { + return; + } + + var typedObj = (TypeWithNoMembers_Wrapper)instance; + BindCore(configuration, ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_TypeWithNoMembers_Wrapper = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Member" }); + + public static void BindCore(IConfiguration configuration, ref TypeWithNoMembers_Wrapper instance, BinderOptions? binderOptions) + { + ValidateConfigurationKeys(typeof(TypeWithNoMembers_Wrapper), s_configKeys_TypeWithNoMembers_Wrapper, configuration, binderOptions); + + if (AsConfigWithChildren(configuration.GetSection("Member")) is IConfigurationSection section0) + { + instance.Member ??= new TypeWithNoMembers(); + } + } + + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + #endregion Core binding extensions. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs index 0e4a97b85b548a..1ffb263c836a1c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections.Generic; using Microsoft.Extensions.Configuration; using Xunit; @@ -249,5 +251,169 @@ private static void AssertRecordIsBound(GeolocationRecord record, int longitude, { Assert.Equal((longitude, latitude), (record.Longitude, record.Latitude)); } + + // These are regression tests for https://github.com/dotnet/runtime/issues/90976 + // Ensure that every emitted identifier name is unique, otherwise name clashes + // will occur and cause compilation to fail. + + [Fact] + public void NameClashTests_NamingPatternsThatCouldCauseClashes() + { + // Potential class between type with closed generic & non generic type. + // Both types start with same substring. The generic arg type's name is + // the same as the suffix of the non generic type's name. + // Manifested in https://github.com/dotnet/runtime/issues/90976. + + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Value"":1}"); + + var c1 = new Cint(); + var c2 = new C(); + + configuration.Bind(c1); + configuration.Bind(c2); + Assert.Equal(1, c1.Value); + Assert.Equal(1, c2.Value); + } + + internal class C + { + public int Value { get; set; } + } + + internal class Cint + { + public int Value { get; set; } + } + + [Fact] + public void NameClashTests_SameTypeName() + { + // Both types have the same name, but one is a nested type. + + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Value"":1}"); + + var c1 = new ClassWithThisIdentifier(); + var c2 = new ClassWithThisIdentifier_Wrapper.ClassWithThisIdentifier(); + + configuration.Bind(c1); + configuration.Bind(c2); + Assert.Equal(1, c1.Value); + Assert.Equal(1, c2.Value); + } + + internal class ClassWithThisIdentifier + { + public int Value { get; set; } + } + + internal class ClassWithThisIdentifier_Wrapper + { + internal class ClassWithThisIdentifier + { + public int Value { get; set; } + } + } + + /// + /// These are regression tests for https://github.com/dotnet/runtime/issues/90909. + /// Ensure that we don't emit root interceptors to handle types/members that + /// are inaccessible to the generated helpers. Tests for inaccessbile transitive members + /// are covered in the shared (reflection/src-gen) , + /// e.g. . + /// + /// + /// In these cases, binding calls will fallback to reflection, as with all cases where + /// we can't correctly resolve the type, such as generic call patterns and boxed objects. + /// + [Fact] + public void MemberAccessibility_InaccessibleNestedTypeAsRootConfig() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Value"":1}"); + + // Ensure no compilation errors; types are skipped. + +#pragma warning disable SYSLIB1104 // Binding logic was not generated for a binder call. + var c1 = new InaccessibleClass_1(); + configuration.Bind(c1); + var c2 = configuration.Get(); + var c3 = configuration.Get(); + + // Generic collections. + + configuration = TestHelpers + .GetConfigurationFromJsonString(@"{""Array"": [{""Value"":1}]}") + .GetSection("Array"); + var c4 = configuration.Get(); + var c5 = configuration.Get>(); + + // Generic types. + + Action? configureOptions = options => options.BindNonPublicProperties = true; + string GetNestedObjectPayload(string propName) => $$""" + { + "{{propName}}": { + "Value": 1 + } + } + """; + + configuration = TestHelpers.GetConfigurationFromJsonString(GetNestedObjectPayload("item1")); + var c6 = configuration.Get>(configureOptions); + + configuration = TestHelpers.GetConfigurationFromJsonString(GetNestedObjectPayload("protectedMember")); + var c7 = configuration.Get>(configureOptions); + var c8 = configuration.Get>(configureOptions); + + configuration = TestHelpers.GetConfigurationFromJsonString(GetNestedObjectPayload("publicMember")); + var c9 = configuration.Get>(configureOptions); + var c10 = configuration.Get>(configureOptions); +#pragma warning disable SYSLIB1104 + + // Reflection fallback. + + Assert.Equal(1, c1.Value); + Assert.Equal(1, c2.Value); + Assert.Equal(1, c3.Value); + + Assert.Equal(1, c4[0].Value); + Assert.Equal(1, c5[0].Value); + Assert.Equal(1, c6["item1"].Value); + + Assert.Equal(1, c7.GetProtectedMember.Value); + Assert.Equal(1, c8.GetProtectedMember.Value); + Assert.Equal(1, c9.PublicMember.Value); + Assert.Equal(1, c10.PublicMember.Value); + } + + private class InaccessibleClass_1() + { + public int Value { get; set; } + } + + protected record InaccessibleClass_2(int Value); + + protected internal class InaccessibleClass_3 + { + public InaccessibleClass_3(int value) => Value = value; + + public int Value { get; } + } + + internal class AccessibleGenericClass + { + protected T ProtectedMember { get; set; } + + public T GetProtectedMember => ProtectedMember; + } + + private class InaccessibleGenericClass + { + public T PublicMember { get; set; } + } + + public class AccessibleClass() + { + public int Value { get; set; } + } } } diff --git a/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs index b0cb90e33d1476..7d280ce7603c2d 100644 --- a/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs @@ -209,28 +209,6 @@ public static bool IsNullableValueType(this ITypeSymbol type, [NotNullWhen(true) return false; } - public static ITypeSymbol[] GetAllTypeArgumentsInScope(this INamedTypeSymbol type) - { - if (!type.IsGenericType) - { - return Array.Empty(); - } - - var args = new List(); - TraverseContainingTypes(type); - return args.ToArray(); - - void TraverseContainingTypes(INamedTypeSymbol current) - { - if (current.ContainingType is INamedTypeSymbol parent) - { - TraverseContainingTypes(parent); - } - - args.AddRange(current.TypeArguments); - } - } - public static ITypeSymbol GetMemberType(this ISymbol member) { Debug.Assert(member is IFieldSymbol or IPropertySymbol); diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 3242dcc5faa4c2..0f3b11b038bc93 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using SourceGenerators; namespace System.Text.Json.SourceGeneration { @@ -1609,9 +1610,12 @@ private static string GetTypeInfoPropertyName(ITypeSymbol type) sb.Append(name); - foreach (ITypeSymbol genericArg in namedType.GetAllTypeArgumentsInScope()) + if (namedType.GetAllTypeArgumentsInScope() is List typeArgsInScope) { - sb.Append(GetTypeInfoPropertyName(genericArg)); + foreach (ITypeSymbol genericArg in typeArgsInScope) + { + sb.Append(GetTypeInfoPropertyName(genericArg)); + } } return sb.ToString(); diff --git a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets index 364f6e1f6682f7..4020a05cb421db 100644 --- a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets +++ b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets @@ -31,6 +31,7 @@ + From 9cdbc87dadbf358206f20f17fed005cdcb253452 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 15:08:14 -0700 Subject: [PATCH 184/345] Replace newline characters in NoWarn (#92062) Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> Co-authored-by: Jan Kotas --- .../nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index a4f34ef2225483..e9462399741c5e 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -263,7 +263,7 @@ The .NET Foundation licenses this file to you under the MIT license. - + From f6cee7c5e7a96858460be1f6711a5cb93057cc24 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Fri, 15 Sep 2023 07:31:13 -0700 Subject: [PATCH 185/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2267753 (#92090) --- .../gen/Resources/xlf/Strings.cs.xlf | 2 +- .../gen/Resources/xlf/Strings.de.xlf | 2 +- .../gen/Resources/xlf/Strings.es.xlf | 2 +- .../gen/Resources/xlf/Strings.fr.xlf | 2 +- .../gen/Resources/xlf/Strings.it.xlf | 2 +- .../gen/Resources/xlf/Strings.ja.xlf | 2 +- .../gen/Resources/xlf/Strings.ko.xlf | 2 +- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 2 +- .../gen/Resources/xlf/Strings.ru.xlf | 2 +- .../gen/Resources/xlf/Strings.tr.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf index 3bc09d74a32702..3f881b123eb971 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Pro volání vazače se nevygenerovala logika vazby. Nepodporované vstupní vzory zahrnují obecná volání a předávání zabalených objektů. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf index 4ef47bf55a3fb4..89583fdc312308 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Für einen Binderaufruf wurde keine Bindungslogik generiert. Nicht unterstützte Eingabemuster umfassen generische Aufrufe und übergeben geschachtelte Objekte. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf index f74c0d799d2a5d..faa309bd384637 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - No se generó la lógica de enlace para una llamada de enlazador. Los patrones de entrada no admitidos incluyen llamadas genéricas y pasar objetos en cuadros. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf index 739f6a85c79492..f8d4c5a5f95d32 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - La logique de liaison n’a pas été générée pour un appel de classeur. Les modèles d’entrée non pris en charge incluent les appels génériques et les objets boxed de passage. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf index 16a25f5fef4a88..54a26a381d6fd1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - La logica di binding non è stata generata per una chiamata binder. I modelli di input non supportati includono chiamate generiche e il passaggio di oggetti in caselle. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf index 260aa898a04f16..b5f1790b0db187 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - バインダー呼び出しのバインド ロジックが生成されませんでした。サポートされていない入力パターンとしては、ジェネリック呼び出し、ボックス化されたオブジェクトの受け渡しなどがあります。 + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf index 5b73d60a47d613..dfcbc040fe3067 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - 바인더 호출에 대한 바인딩 논리가 생성되지 않았습니다. 지원되지 않는 입력 패턴에는 제네릭 호출 및 boxed 개체 전달이 포함됩니다. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf index 8a675ed3e3fa03..1834dac0e73f15 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Nie wygenerowano logiki powiązania dla wywołania integratora. Nieobsługiwane wzorce wejściowe obejmują wywołania ogólne i przekazywanie obiektów w ramce. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf index 5f54f60e4c13cc..e15e781b7abfdc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - A lógica de associação não foi gerada para uma chamada de associador. Os padrões de entrada sem suporte incluem chamadas genéricas e passagem de objetos em caixa. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf index bf40ee5af2c390..00e4d7418b5db6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Логика привязки не была создана для вызова модуля привязки. К неподдерживаемым шаблонам ввода относятся универсальные вызовы и передача упакованных объектов. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf index 732554a8893005..cd53389a70ed28 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Bir bağlayıcı çağrısı için bağlama mantığı oluşturulmadı. Desteklenmeyen giriş desenleri genel çağrılar ve geçici kutulu nesneler içeriyor. + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf index f35cf502782512..55c321ec0d801f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - 未为联编程序调用生成绑定逻辑。不支持的输入模式包括泛型调用和传递装箱对象。 + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf index ff843029507c1f..edc74d0c17ad97 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - 未產生文件夾呼叫的繫結邏輯。不支援的輸入模式包括一般呼叫和傳遞方塊物件。 + Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. From 740081f22a3ea86d56e98a182a9086f9c07835ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 09:36:40 -0700 Subject: [PATCH 186/345] [release/8.0] Update FixupPrecode and StubPrecode types for ARM (#92075) * Update FixupPrecode and StubPrecode types for ARM Co-authored-by: Jan Vorlicek * Update ThisPtrRetBufPrecode and NDirectImportPrecode types for arm Co-authored-by: Jan Vorlicek * Addressing PR feedback - remove unnecessary #ifdef's * FIx riscv64 build break due to NDirectImportPrecode::Type conflict with ThisPtrRetBufPrecode::Type --------- Co-authored-by: Tom McDonald Co-authored-by: Jan Vorlicek --- src/coreclr/vm/arm/cgencpu.h | 2 +- src/coreclr/vm/precode.h | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/arm/cgencpu.h b/src/coreclr/vm/arm/cgencpu.h index d31700e3477a40..6538cea705a56a 100644 --- a/src/coreclr/vm/arm/cgencpu.h +++ b/src/coreclr/vm/arm/cgencpu.h @@ -996,7 +996,7 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool // Precode to shuffle this and retbuf for closed delegates over static methods with return buffer struct ThisPtrRetBufPrecode { - static const int Type = 0x46; + static const int Type = 0x01; // mov r12, r0 // mov r0, r1 diff --git a/src/coreclr/vm/precode.h b/src/coreclr/vm/precode.h index 158c1ab08f5545..3f6a2f532c4e67 100644 --- a/src/coreclr/vm/precode.h +++ b/src/coreclr/vm/precode.h @@ -36,8 +36,8 @@ EXTERN_C VOID STDCALL PrecodeRemotingThunk(); #elif defined(TARGET_ARM) -#define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN -#define OFFSETOF_PRECODE_TYPE 3 +#define SIZEOF_PRECODE_BASE CODE_SIZE_ALIGN * 2 +#define OFFSETOF_PRECODE_TYPE 7 #elif defined(TARGET_LOONGARCH64) @@ -100,7 +100,7 @@ struct StubPrecode static const int Type = 0x4A; static const SIZE_T CodeSize = 24; #elif defined(TARGET_ARM) - static const int Type = 0xCF; + static const int Type = 0xFF; static const SIZE_T CodeSize = 12; #elif defined(TARGET_LOONGARCH64) static const int Type = 0x4; @@ -189,7 +189,7 @@ typedef DPTR(StubPrecode) PTR_StubPrecode; // (This is fake precode. VTable slot does not point to it.) struct NDirectImportPrecode : StubPrecode { - static const int Type = 0x01; + static const int Type = 0x05; void Init(NDirectImportPrecode* pPrecodeRX, MethodDesc* pMD, LoaderAllocator *pLoaderAllocator); @@ -237,7 +237,7 @@ struct FixupPrecode static const SIZE_T CodeSize = 24; static const int FixupCodeOffset = 8; #elif defined(TARGET_ARM) - static const int Type = 0xFF; + static const int Type = 0xCF; static const SIZE_T CodeSize = 12; static const int FixupCodeOffset = 4 + THUMB_CODE; #elif defined(TARGET_LOONGARCH64) @@ -614,4 +614,8 @@ static_assert_no_msg(FixupPrecode::Type != NDirectImportPrecode::Type); static_assert_no_msg(FixupPrecode::Type != ThisPtrRetBufPrecode::Type); static_assert_no_msg(NDirectImportPrecode::Type != ThisPtrRetBufPrecode::Type); +// Verify that the base type for each precode fits into each specific precode type +static_assert_no_msg(sizeof(Precode) <= sizeof(NDirectImportPrecode)); +static_assert_no_msg(sizeof(Precode) <= sizeof(FixupPrecode)); +static_assert_no_msg(sizeof(Precode) <= sizeof(ThisPtrRetBufPrecode)); #endif // __PRECODE_H__ From d8a419ae772988d7ebaa6cebaf5570d6abd84e7c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 09:40:22 -0700 Subject: [PATCH 187/345] Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230914.2 (#92121) Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23458.2 -> To Version 3.11.0-beta1.23464.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 69ae2ed593410b..5d31a0830de329 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -371,13 +371,13 @@ https://github.com/dotnet/roslyn 1b7a6f807cb8ce709048debae6b771f4705a697a - + https://github.com/dotnet/roslyn-analyzers - 249601bb0afe8c481f01300012610f1ac182dfa5 + 7ec4e8924bcbc469e00aa2bda84251c3e90aa96e - + https://github.com/dotnet/roslyn-analyzers - 249601bb0afe8c481f01300012610f1ac182dfa5 + 7ec4e8924bcbc469e00aa2bda84251c3e90aa96e https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index 4dc7e62f9ec17c..d5c3bfcb0fd9f0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.23458.2 - 8.0.0-preview.23458.2 + 3.11.0-beta1.23464.2 + 8.0.0-preview.23464.2 diff --git a/eng/Versions.props b/eng/Versions.props index d5c3bfcb0fd9f0..9223996861d8fd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23463.3 - 1.0.0-prerelease.23463.3 - 1.0.0-prerelease.23463.3 - 1.0.0-prerelease.23463.3 - 1.0.0-prerelease.23463.3 - 1.0.0-prerelease.23463.3 + 1.0.0-prerelease.23464.6 + 1.0.0-prerelease.23464.6 + 1.0.0-prerelease.23464.6 + 1.0.0-prerelease.23464.6 + 1.0.0-prerelease.23464.6 + 1.0.0-prerelease.23464.6 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 From bb44ca5adee2ee1d139ae3780db8508c752d06de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 11:19:06 -0700 Subject: [PATCH 191/345] [release/8.0] fix ReceiveFrom with dual mode socket (#92103) * fix ReceiveFrom with dual mode socket * test * feedback --------- Co-authored-by: wfurt Co-authored-by: Anton Firszov --- .../src/Resources/Strings.resx | 2 +- .../src/System/Net/IPEndPoint.cs | 6 +-- .../tests/FunctionalTests/IPEndPointTest.cs | 16 ++++++- .../Net/Sockets/SocketAsyncEventArgs.cs | 17 +++++-- .../tests/FunctionalTests/ReceiveFrom.cs | 46 +++++++++++++++++++ 5 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx index 958a0e2e269f99..65d4809398b3b2 100644 --- a/src/libraries/System.Net.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Primitives/src/Resources/Strings.resx @@ -64,7 +64,7 @@ This property is not implemented by this class. - The AddressFamily {0} is not valid for the {1} end point, use {2} instead. + The AddressFamily {0} is not valid for the {1} end point. The supplied {0} is an invalid size for the {1} end point. diff --git a/src/libraries/System.Net.Primitives/src/System/Net/IPEndPoint.cs b/src/libraries/System.Net.Primitives/src/System/Net/IPEndPoint.cs index 3531f266e6c504..ff47d2fbc515ef 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/IPEndPoint.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/IPEndPoint.cs @@ -155,9 +155,9 @@ public override EndPoint Create(SocketAddress socketAddress) { ArgumentNullException.ThrowIfNull(socketAddress); - if (socketAddress.Family != AddressFamily) - { - throw new ArgumentException(SR.Format(SR.net_InvalidAddressFamily, socketAddress.Family.ToString(), GetType().FullName, AddressFamily.ToString()), nameof(socketAddress)); + if (socketAddress.Family is not (AddressFamily.InterNetwork or AddressFamily.InterNetworkV6)) + { + throw new ArgumentException(SR.Format(SR.net_InvalidAddressFamily, socketAddress.Family.ToString(), GetType().FullName), nameof(socketAddress)); } int minSize = AddressFamily == AddressFamily.InterNetworkV6 ? SocketAddress.IPv6AddressSize : SocketAddress.IPv4AddressSize; diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs index bb9b95d438e99f..c233dee628dfeb 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs @@ -143,6 +143,19 @@ public static void ToString_Invoke_ReturnsExpected(IPEndPoint endPoint, string e Assert.Equal(expected, endPoint.ToString()); } + [Fact] + public static void Create_DifferentAF_Success() + { + SocketAddress sa = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.GetMaximumAddressSize(AddressFamily.InterNetworkV6)); + var ep = new IPEndPoint(IPAddress.IPv6Any, 0); + Assert.NotNull(ep.Create(sa)); + + sa = new SocketAddress(AddressFamily.InterNetworkV6); + ep = new IPEndPoint(IPAddress.Any, 0); + + Assert.NotNull(ep.Create(sa)); + } + public static IEnumerable Serialize_TestData() { yield return new object[] { new IPAddress(2), 16 }; @@ -195,8 +208,7 @@ public static void Create_NullSocketAddress_ThrowsArgumentNullException() public static IEnumerable Create_InvalidAddressFamily_TestData() { - yield return new object[] { new IPEndPoint(2, 500), new SocketAddress(Sockets.AddressFamily.InterNetworkV6) }; - yield return new object[] { new IPEndPoint(IPAddress.Parse("192.169.0.9"), 500), new SocketAddress(Sockets.AddressFamily.InterNetworkV6) }; + yield return new object[] { new IPEndPoint(2, 500), new SocketAddress(Sockets.AddressFamily.Unknown) }; yield return new object[] { new IPEndPoint(IPAddress.Parse("0:0:0:0:0:0:0:1"), 500), new SocketAddress(Sockets.AddressFamily.InterNetwork) }; } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index e04739d5fe7a6e..e94d862571a0f8 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -927,13 +927,13 @@ internal void FinishOperationSyncSuccess(int bytesTransferred, SocketFlags flags { try { - if (_remoteEndPoint!.AddressFamily == _socketAddress!.Family) + if (_remoteEndPoint!.AddressFamily == AddressFamily.InterNetworkV6 && _socketAddress!.Family == AddressFamily.InterNetwork) { - _remoteEndPoint = _remoteEndPoint!.Create(_socketAddress); + _remoteEndPoint = new IPEndPoint(_socketAddress.GetIPAddress().MapToIPv6(), _socketAddress.GetPort()); } - else if (_remoteEndPoint!.AddressFamily == AddressFamily.InterNetworkV6 && _socketAddress.Family == AddressFamily.InterNetwork) + else { - _remoteEndPoint = new IPEndPoint(_socketAddress.GetIPAddress().MapToIPv6(), _socketAddress.GetPort()); + _remoteEndPoint = _remoteEndPoint!.Create(_socketAddress!); } } catch @@ -949,7 +949,14 @@ internal void FinishOperationSyncSuccess(int bytesTransferred, SocketFlags flags { try { - _remoteEndPoint = _remoteEndPoint!.Create(_socketAddress!); + if (_remoteEndPoint!.AddressFamily == AddressFamily.InterNetworkV6 && _socketAddress!.Family == AddressFamily.InterNetwork) + { + _remoteEndPoint = new IPEndPoint(_socketAddress.GetIPAddress().MapToIPv6(), _socketAddress.GetPort()); + } + else + { + _remoteEndPoint = _remoteEndPoint!.Create(_socketAddress!); + } } catch { diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs index 1a5ec7d05d28e9..1ec2adeadcf517 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs @@ -168,6 +168,52 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) } } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task ReceiveSent_DualMode_Success(bool ipv4) + { + const int Offset = 10; + const int DatagramSize = 256; + const int DatagramsToSend = 16; + + IPAddress address = ipv4 ? IPAddress.Loopback : IPAddress.IPv6Loopback; + using Socket receiver = new Socket(SocketType.Dgram, ProtocolType.Udp); + using Socket sender = new Socket(SocketType.Dgram, ProtocolType.Udp); + if (receiver.DualMode != true || sender.DualMode != true) + { + throw new SkipException("DualMode not available"); + } + + ConfigureNonBlocking(sender); + ConfigureNonBlocking(receiver); + + receiver.BindToAnonymousPort(address); + sender.BindToAnonymousPort(address); + + byte[] sendBuffer = new byte[DatagramSize]; + var receiveInternalBuffer = new byte[DatagramSize + Offset]; + var emptyBuffer = new byte[Offset]; + ArraySegment receiveBuffer = new ArraySegment(receiveInternalBuffer, Offset, DatagramSize); + + Random rnd = new Random(0); + + for (int i = 0; i < DatagramsToSend; i++) + { + rnd.NextBytes(sendBuffer); + sender.SendTo(sendBuffer, receiver.LocalEndPoint); + + IPEndPoint remoteEp = new IPEndPoint(ipv4 ? IPAddress.Any : IPAddress.IPv6Any, 0); + + SocketReceiveFromResult result = await ReceiveFromAsync(receiver, receiveBuffer, remoteEp); + + Assert.Equal(DatagramSize, result.ReceivedBytes); + AssertExtensions.SequenceEqual(emptyBuffer, new ReadOnlySpan(receiveInternalBuffer, 0, Offset)); + AssertExtensions.SequenceEqual(sendBuffer, new ReadOnlySpan(receiveInternalBuffer, Offset, DatagramSize)); + Assert.Equal(sender.LocalEndPoint, result.RemoteEndPoint); + } + } + [Theory] [InlineData(false)] [InlineData(true)] From f262154e0a2129e51313bb1b35aa6aeee4dca4fb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:51:31 -0700 Subject: [PATCH 192/345] [release/8.0] [NativeAOT] Switch macOS to mmap thunks like iOS platforms (#92136) * Switch macOS to mmap thunks like iOS platforms * Relax expected binary size --------- Co-authored-by: Filip Navara Co-authored-by: Jan Kotas --- .../BuildIntegration/Microsoft.NETCore.Native.Unix.targets | 2 +- src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt | 2 +- src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index 409fcb654e919d..d30e7e73578eaa 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -121,7 +121,7 @@ The .NET Foundation licenses this file to you under the MIT license. - + diff --git a/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt index 3cbaa6e2f253a6..f3d48797c2184a 100644 --- a/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/Full/CMakeLists.txt @@ -6,7 +6,7 @@ project(Runtime) # Include auto-generated files on include path set(CMAKE_INCLUDE_CURRENT_DIR ON) -if (CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_OSX) +if (CLR_CMAKE_TARGET_APPLE) list(APPEND RUNTIME_SOURCES_ARCH_ASM ${ARCH_SOURCES_DIR}/ThunkPoolThunks.${ASM_SUFFIX} ) diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index e628938c57db82..52a86654a03166 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -22,7 +22,7 @@ static int Main() long lowerBound, upperBound; lowerBound = 1300 * 1024; // ~1.3 MB - upperBound = 1750 * 1024; // ~1.75 MB + upperBound = 1800 * 1024; // ~1.8 MB if (fileSize < lowerBound || fileSize > upperBound) { From 90d54f9f9e68c317cc2c7d1c94ac84d9d2489848 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Fri, 15 Sep 2023 17:41:58 -0700 Subject: [PATCH 193/345] [release/8.0] Improve binder gen binding logic (init, member binding, polymorphism) (#92118) --- .../ConfigurationBindingGenerator.Emitter.cs | 178 ------ .../ConfigurationBindingGenerator.Parser.cs | 279 ++++----- .../Emitter/ConfigurationBinder.cs | 14 +- .../Emitter/CoreBindingHelpers.cs | 588 ++++++++++++------ .../Emitter/ExceptionMessages.cs | 0 .../gen/{Helpers => }/Emitter/Helpers.cs | 18 +- .../OptionsBuilderConfigurationExtensions.cs | 0 ...onfigurationServiceCollectionExtensions.cs | 0 ...nfiguration.Binder.SourceGeneration.csproj | 51 +- .../gen/Model/ConfigurationSectionSpec.cs | 14 - .../gen/Model/InitializationStrategy.cs | 14 - .../{Helpers => }/Parser/BinderInvocation.cs | 0 .../Parser/ConfigurationBinder.cs | 31 +- .../gen/{Helpers => }/Parser/Diagnostics.cs | 0 .../gen/{Helpers => }/Parser/Extensions.cs | 6 + .../OptionsBuilderConfigurationExtensions.cs | 28 +- ...onfigurationServiceCollectionExtensions.cs | 27 +- .../InterceptorLocationInfo.cs | 0 .../gen/{Model => Specs}/KnownTypeSymbols.cs | 0 .../{Model => Specs/Members}/MemberSpec.cs | 0 .../{Model => Specs/Members}/ParameterSpec.cs | 0 .../{Model => Specs/Members}/PropertySpec.cs | 2 +- .../gen/{Helpers => Specs}/MethodsToGen.cs | 0 .../{Model => Specs}/SourceGenerationSpec.cs | 0 .../{Model => Specs/Types}/CollectionSpec.cs | 20 +- .../gen/Specs/Types/ComplexTypeSpec.cs | 29 + .../{Model => Specs/Types}/NullableSpec.cs | 9 +- .../gen/{Model => Specs/Types}/ObjectSpec.cs | 8 +- .../Types/SimpleTypeSpec.cs} | 20 +- .../gen/{Model => Specs/Types}/TypeSpec.cs | 14 +- .../ConfigurationBinderTests.TestClasses.cs | 68 +- .../tests/Common/ConfigurationBinderTests.cs | 135 +++- ...ind_ParseTypeFromMethodParam.generated.txt | 72 +++ .../GeneratorTests.Baselines.cs | 92 +++ .../GeneratorTests.Helpers.cs | 3 +- .../SourceGenerationTests/GeneratorTests.cs | 59 +- 36 files changed, 1064 insertions(+), 715 deletions(-) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Emitter/ConfigurationBinder.cs (94%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Emitter/CoreBindingHelpers.cs (60%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Emitter/ExceptionMessages.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Emitter/Helpers.cs (96%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Emitter/OptionsBuilderConfigurationExtensions.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Emitter/OptionsConfigurationServiceCollectionExtensions.cs (100%) delete mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ConfigurationSectionSpec.cs delete mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/InitializationStrategy.cs rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Parser/BinderInvocation.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Parser/ConfigurationBinder.cs (88%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Parser/Diagnostics.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Parser/Extensions.cs (89%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Parser/OptionsBuilderConfigurationExtensions.cs (77%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => }/Parser/OptionsConfigurationServiceCollectionExtensions.cs (77%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => Specs}/InterceptorLocationInfo.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs}/KnownTypeSymbols.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Members}/MemberSpec.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Members}/ParameterSpec.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Members}/PropertySpec.cs (95%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Helpers => Specs}/MethodsToGen.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs}/SourceGenerationSpec.cs (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Types}/CollectionSpec.cs (64%) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Types}/NullableSpec.cs (73%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Types}/ObjectSpec.cs (65%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model/ParsableFromStringSpec.cs => Specs/Types/SimpleTypeSpec.cs} (71%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/gen/{Model => Specs/Types}/TypeSpec.cs (78%) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs index cb67c7ee1f5fb9..7206d549041147 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs @@ -1,10 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Immutable; -using System.Diagnostics; -using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; using SourceGenerators; @@ -16,12 +13,6 @@ private sealed partial class Emitter { private readonly SourceProductionContext _context; private readonly SourceGenerationSpec _sourceGenSpec; - - private bool _emitBlankLineBeforeNextStatement; - private int _valueSuffixIndex; - - private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]")); - private readonly SourceWriter _writer = new(); public Emitter(SourceProductionContext context, SourceGenerationSpec sourceGenSpec) @@ -64,163 +55,6 @@ file static class {{Identifier.BindingExtensions}} _context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText()); } - private void EmitBindCoreCall( - TypeSpec type, - string memberAccessExpr, - string configArgExpr, - InitializationKind initKind, - Action? writeOnSuccess = null) - { - Debug.Assert(type.CanInitialize); - - if (!type.NeedsMemberBinding) - { - EmitObjectInit(memberAccessExpr, initKind); - return; - } - - string tempIdentifier = GetIncrementalIdentifier(Identifier.temp); - if (initKind is InitializationKind.AssignmentWithNullCheck) - { - Debug.Assert(!type.IsValueType); - _writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};"); - EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck); - } - else if (initKind is InitializationKind.None && type.IsValueType) - { - EmitBindCoreCall(tempIdentifier, InitializationKind.Declaration); - _writer.WriteLine($"{memberAccessExpr} = {tempIdentifier};"); - } - else - { - EmitBindCoreCall(memberAccessExpr, initKind); - } - - void EmitBindCoreCall(string instanceExpr, InitializationKind initKind) - { - string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {instanceExpr}, {Identifier.binderOptions});"; - EmitObjectInit(instanceExpr, initKind); - _writer.WriteLine(bindCoreCall); - writeOnSuccess?.Invoke(instanceExpr); - } - - void EmitObjectInit(string instanceExpr, InitializationKind initKind) - { - if (initKind is not InitializationKind.None) - { - this.EmitObjectInit(type, instanceExpr, initKind, configArgExpr); - } - } - } - - private void EmitBindLogicFromString( - ParsableFromStringSpec type, - string sectionValueExpr, - string sectionPathExpr, - Action? writeOnSuccess, - bool checkForNullSectionValue, - bool useIncrementalStringValueIdentifier) - { - StringParsableTypeKind typeKind = type.StringParsableTypeKind; - Debug.Assert(typeKind is not StringParsableTypeKind.None); - - string nonNull_StringValue_Identifier = useIncrementalStringValueIdentifier ? GetIncrementalIdentifier(Identifier.value) : Identifier.value; - string stringValueToParse_Expr = checkForNullSectionValue ? nonNull_StringValue_Identifier : sectionValueExpr; - - string parsedValueExpr; - if (typeKind is StringParsableTypeKind.AssignFromSectionValue) - { - parsedValueExpr = stringValueToParse_Expr; - } - else if (typeKind is StringParsableTypeKind.Enum) - { - parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})"; - } - else - { - parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})"; - } - - if (!checkForNullSectionValue) - { - InvokeWriteOnSuccess(); - } - else - { - EmitStartBlock($"if ({sectionValueExpr} is string {nonNull_StringValue_Identifier})"); - InvokeWriteOnSuccess(); - EmitEndBlock(); - } - - void InvokeWriteOnSuccess() => writeOnSuccess?.Invoke(parsedValueExpr); - } - - private bool EmitObjectInit(TypeSpec type, string memberAccessExpr, InitializationKind initKind, string configArgExpr) - { - Debug.Assert(type.CanInitialize && initKind is not InitializationKind.None); - - string initExpr; - CollectionSpec? collectionType = type as CollectionSpec; - - string effectiveDisplayString = type.DisplayString; - if (collectionType is not null) - { - if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array }) - { - initExpr = $"new {s_arrayBracketsRegex.Replace(effectiveDisplayString, "[0]", 1)}"; - } - else - { - effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString; - initExpr = $"new {effectiveDisplayString}()"; - } - } - else if (type.InitializationStrategy is InitializationStrategy.ParameterlessConstructor) - { - initExpr = $"new {effectiveDisplayString}()"; - } - else - { - Debug.Assert(type.InitializationStrategy is InitializationStrategy.ParameterizedConstructor); - string initMethodIdentifier = GetInitalizeMethodDisplayString(((ObjectSpec)type)); - initExpr = $"{initMethodIdentifier}({configArgExpr}, {Identifier.binderOptions})"; - } - - if (initKind == InitializationKind.Declaration) - { - Debug.Assert(!memberAccessExpr.Contains(".")); - _writer.WriteLine($"var {memberAccessExpr} = {initExpr};"); - } - else if (initKind == InitializationKind.AssignmentWithNullCheck) - { - if (collectionType is CollectionSpec - { - InitializationStrategy: InitializationStrategy.ParameterizedConstructor or InitializationStrategy.ToEnumerableMethod - }) - { - if (collectionType.InitializationStrategy is InitializationStrategy.ParameterizedConstructor) - { - _writer.WriteLine($"{memberAccessExpr} = {memberAccessExpr} is null ? {initExpr} : new {effectiveDisplayString}({memberAccessExpr});"); - } - else - { - _writer.WriteLine($"{memberAccessExpr} = {memberAccessExpr} is null ? {initExpr} : {memberAccessExpr}.{collectionType.ToEnumerableMethodCall!};"); - } - } - else - { - _writer.WriteLine($"{memberAccessExpr} ??= {initExpr};"); - } - } - else - { - Debug.Assert(initKind is InitializationKind.SimpleAssignment); - _writer.WriteLine($"{memberAccessExpr} = {initExpr};"); - } - - return true; - } - private void EmitInterceptsLocationAttrDecl() { _writer.WriteLine(); @@ -250,18 +84,6 @@ private void EmitUsingStatements() _writer.WriteLine($"using {@namespace};"); } } - - private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn) - { - string returnPostfix = voidReturn ? string.Empty : " null"; - _writer.WriteLine($$""" - if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}})) - { - return{{returnPostfix}}; - } - """); - _writer.WriteLine(); - } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index deb0f4c0aabc0d..2a6f5d2126e8c8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -52,15 +52,15 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm if (SymbolEqualityComparer.Default.Equals(candidateBinderType, _typeSymbols.ConfigurationBinder)) { - RegisterMethodInvocation_ConfigurationBinder(invocation); + ParseInvocation_ConfigurationBinder(invocation); } else if (SymbolEqualityComparer.Default.Equals(candidateBinderType, _typeSymbols.OptionsBuilderConfigurationExtensions)) { - RegisterMethodInvocation_OptionsBuilderExt(invocation); + ParseInvocation_OptionsBuilderExt(invocation); } else if (SymbolEqualityComparer.Default.Equals(candidateBinderType, _typeSymbols.OptionsConfigurationServiceCollectionExtensions)) { - RegisterMethodInvocation_ServiceCollectionExt(invocation); + ParseInvocation_ServiceCollectionExt(invocation); } } @@ -120,7 +120,7 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || if (IsNullable(type, out ITypeSymbol? underlyingType)) { - spec = TryGetTypeSpec(underlyingType, Diagnostics.NullableUnderlyingTypeNotSupported, out TypeSpec? underlyingTypeSpec) + spec = MemberTypeIsBindable(type, underlyingType, Diagnostics.NullableUnderlyingTypeNotSupported, out TypeSpec? underlyingTypeSpec) ? new NullableSpec(type, underlyingTypeSpec) : null; } @@ -165,13 +165,7 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || RegisterTypeDiagnostic(type, diag); } - if (spec is null) - { - return null; - } - - string @namespace = spec.Namespace; - if (@namespace is not null and not "") + if (spec is { Namespace: string @namespace } && @namespace is not "") { _sourceGenSpec.Namespaces.Add(@namespace); } @@ -179,28 +173,36 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || return _createdSpecs[type] = spec; } - private void RegisterTypeForBindCoreMainGen(TypeSpec typeSpec) + private bool TryRegisterTypeForBindCoreMainGen(ComplexTypeSpec type) { - if (typeSpec.NeedsMemberBinding) + if (type.HasBindableMembers) { - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec); - RegisterTypeForBindCoreGen(typeSpec); - _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + bool registeredForBindCoreGen = TryRegisterTypeForBindCoreGen(type); + Debug.Assert(registeredForBindCoreGen); + + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, type); + Register_AsConfigWithChildren_HelperForGen_IfRequired(type); + return true; } + + return false; } - private void RegisterTypeForBindCoreGen(TypeSpec typeSpec) + private bool TryRegisterTypeForBindCoreGen(ComplexTypeSpec type) { - if (typeSpec.NeedsMemberBinding) + if (type.HasBindableMembers) { - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec); + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, type); + return true; } + + return false; } private void RegisterTypeForGetCoreGen(TypeSpec typeSpec) { RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec); - _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + Register_AsConfigWithChildren_HelperForGen_IfRequired(typeSpec); } private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type) @@ -214,11 +216,19 @@ private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, Typ _sourceGenSpec.MethodsToGen_CoreBindingHelper |= method; } + private void Register_AsConfigWithChildren_HelperForGen_IfRequired(TypeSpec possibleComplexType) + { + if (possibleComplexType is ComplexTypeSpec) + { + _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + } + } + /// /// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind, - /// which is handled by + /// which is handled by /// - private void RegisterAsInterceptor(Enum method, IInvocationOperation operation) => + private void RegisterInterceptor(Enum method, IInvocationOperation operation) => _sourceGenSpec.InterceptionInfo.RegisterCacheEntry(method, new InterceptorLocationInfo(operation)); private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType) @@ -339,61 +349,33 @@ private bool IsParsableFromString(ITypeSymbol type, out StringParsableTypeKind t } } - private bool TryGetTypeSpec(ITypeSymbol type, DiagnosticDescriptor descriptor, out TypeSpec? spec) + private EnumerableSpec? CreateArraySpec(IArrayTypeSymbol arrayTypeSymbol) { - spec = GetOrCreateTypeSpec(type); + ITypeSymbol elementTypeSymbol = arrayTypeSymbol.ElementType; - if (spec is null) - { - RegisterUnsupportedType(type, descriptor); - return false; - } - - return true; - } - - private EnumerableSpec? CreateArraySpec(IArrayTypeSymbol arrayType) - { - if (!TryGetTypeSpec(arrayType.ElementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec)) + if (!MemberTypeIsBindable(arrayTypeSymbol, elementTypeSymbol, Diagnostics.ElementTypeNotSupported, out TypeSpec elementTypeSpec)) { return null; } - // We want a BindCore method for List as a temp holder for the array values. We know the element type is supported. - EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!; - RegisterTypeForBindCoreGen(listSpec); + // We want a BindCore method for List as a temp holder for the array values. + // Since the element type is supported, we can certainly a list of elements. + EnumerableSpec listTypeSpec = (EnumerableSpec)GetOrCreateTypeSpec(_typeSymbols.List.Construct(elementTypeSymbol)); - EnumerableSpec spec = new EnumerableSpec(arrayType) + EnumerableSpec spec = new EnumerableSpec(arrayTypeSymbol) { - ElementType = elementSpec, - ConcreteType = listSpec, - InitializationStrategy = InitializationStrategy.Array, + ElementType = elementTypeSpec, + InstantiationStrategy = InstantiationStrategy.Array, PopulationStrategy = CollectionPopulationStrategy.Cast_Then_Add, // Using the concrete list type as a temp holder. - ToEnumerableMethodCall = null, + TypeToInstantiate = listTypeSpec, + PopulationCastType = null, }; - Debug.Assert(spec.CanInitialize); - RegisterTypeForBindCoreGen(spec); - + bool registeredForBindCore = TryRegisterTypeForBindCoreGen(listTypeSpec) && TryRegisterTypeForBindCoreGen(spec); + Debug.Assert(registeredForBindCore); return spec; } - private bool IsSupportedArrayType(ITypeSymbol type) - { - if (type is not IArrayTypeSymbol arrayType) - { - return false; - } - - if (arrayType.Rank > 1) - { - RegisterUnsupportedType(arrayType, Diagnostics.MultiDimArraysNotSupported); - return false; - } - - return true; - } - private CollectionSpec? CreateCollectionSpec(INamedTypeSymbol type) { CollectionSpec? spec; @@ -407,38 +389,38 @@ private bool IsSupportedArrayType(ITypeSymbol type) spec = CreateEnumerableSpec(type); } - if (spec is not null) + if (spec is null) { - RegisterTypeForBindCoreGen(spec); - spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage; + return null; } + bool registerForBindCoreGen = TryRegisterTypeForBindCoreGen(spec); + Debug.Assert(registerForBindCoreGen); return spec; } private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol keyType, ITypeSymbol elementType) { - if (!TryGetTypeSpec(keyType, Diagnostics.DictionaryKeyNotSupported, out TypeSpec keySpec) || - !TryGetTypeSpec(elementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec)) + if (!MemberTypeIsBindable(type, keyType, Diagnostics.DictionaryKeyNotSupported, out TypeSpec keySpec) || + !MemberTypeIsBindable(type, elementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec)) { return null; } - if (keySpec.SpecKind != TypeSpecKind.ParsableFromString) + if (keySpec.SpecKind is not TypeSpecKind.ParsableFromString) { RegisterUnsupportedType(type, Diagnostics.DictionaryKeyNotSupported); return null; } - InitializationStrategy constructionStrategy; + InstantiationStrategy constructionStrategy; CollectionPopulationStrategy populationStrategy; - INamedTypeSymbol? concreteType = null; + INamedTypeSymbol? typeToInstantiate = null; INamedTypeSymbol? populationCastType = null; - string? toEnumerableMethodCall = null; if (HasPublicParameterLessCtor(type)) { - constructionStrategy = InitializationStrategy.ParameterlessConstructor; + constructionStrategy = InstantiationStrategy.ParameterlessConstructor; if (HasAddMethod(type, keyType, elementType)) { @@ -457,17 +439,16 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k } else if (IsInterfaceMatch(type, _typeSymbols.GenericIDictionary_Unbound) || IsInterfaceMatch(type, _typeSymbols.IDictionary)) { - concreteType = _typeSymbols.Dictionary; - constructionStrategy = InitializationStrategy.ParameterlessConstructor; + typeToInstantiate = _typeSymbols.Dictionary; + constructionStrategy = InstantiationStrategy.ParameterlessConstructor; populationStrategy = CollectionPopulationStrategy.Add; } else if (IsInterfaceMatch(type, _typeSymbols.IReadOnlyDictionary_Unbound)) { - concreteType = _typeSymbols.Dictionary; + typeToInstantiate = _typeSymbols.Dictionary; populationCastType = _typeSymbols.GenericIDictionary; - constructionStrategy = InitializationStrategy.ToEnumerableMethod; + constructionStrategy = InstantiationStrategy.ToEnumerableMethod; populationStrategy = CollectionPopulationStrategy.Cast_Then_Add; - toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)"; _sourceGenSpec.Namespaces.Add("System.Linq"); } else @@ -476,38 +457,37 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k return null; } + Debug.Assert(!(populationStrategy is CollectionPopulationStrategy.Cast_Then_Add && populationCastType is null)); + DictionarySpec spec = new(type) { KeyType = (ParsableFromStringSpec)keySpec, ElementType = elementSpec, - InitializationStrategy = constructionStrategy, + InstantiationStrategy = constructionStrategy, PopulationStrategy = populationStrategy, - ToEnumerableMethodCall = toEnumerableMethodCall, + TypeToInstantiate = ConstructGenericCollectionSpecIfRequired(typeToInstantiate, keyType, elementType) as DictionarySpec, + PopulationCastType = ConstructGenericCollectionSpecIfRequired(populationCastType, keyType, elementType) as DictionarySpec, }; - Debug.Assert(!(populationStrategy is CollectionPopulationStrategy.Cast_Then_Add && populationCastType is null)); - spec.ConcreteType = ConstructGenericCollectionSpecIfRequired(concreteType, keyType, elementType); - spec.PopulationCastType = ConstructGenericCollectionSpecIfRequired(populationCastType, keyType, elementType); - return spec; } private EnumerableSpec? CreateEnumerableSpec(INamedTypeSymbol type) { if (!TryGetElementType(type, out ITypeSymbol? elementType) || - !TryGetTypeSpec(elementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec)) + !MemberTypeIsBindable(type, elementType, Diagnostics.ElementTypeNotSupported, out TypeSpec elementSpec)) { return null; } - InitializationStrategy constructionStrategy; + InstantiationStrategy instantiationStrategy; CollectionPopulationStrategy populationStrategy; - INamedTypeSymbol? concreteType = null; + INamedTypeSymbol? typeToInstantiate = null; INamedTypeSymbol? populationCastType = null; if (HasPublicParameterLessCtor(type)) { - constructionStrategy = InitializationStrategy.ParameterlessConstructor; + instantiationStrategy = InstantiationStrategy.ParameterlessConstructor; if (HasAddMethod(type, elementType)) { @@ -527,35 +507,35 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k else if (IsInterfaceMatch(type, _typeSymbols.GenericICollection_Unbound) || IsInterfaceMatch(type, _typeSymbols.GenericIList_Unbound)) { - concreteType = _typeSymbols.List; - constructionStrategy = InitializationStrategy.ParameterlessConstructor; + typeToInstantiate = _typeSymbols.List; + instantiationStrategy = InstantiationStrategy.ParameterlessConstructor; populationStrategy = CollectionPopulationStrategy.Add; } else if (IsInterfaceMatch(type, _typeSymbols.GenericIEnumerable_Unbound)) { - concreteType = _typeSymbols.List; + typeToInstantiate = _typeSymbols.List; populationCastType = _typeSymbols.GenericICollection; - constructionStrategy = InitializationStrategy.ParameterizedConstructor; + instantiationStrategy = InstantiationStrategy.ParameterizedConstructor; populationStrategy = CollectionPopulationStrategy.Cast_Then_Add; } else if (IsInterfaceMatch(type, _typeSymbols.ISet_Unbound)) { - concreteType = _typeSymbols.HashSet; - constructionStrategy = InitializationStrategy.ParameterlessConstructor; + typeToInstantiate = _typeSymbols.HashSet; + instantiationStrategy = InstantiationStrategy.ParameterlessConstructor; populationStrategy = CollectionPopulationStrategy.Add; } else if (IsInterfaceMatch(type, _typeSymbols.IReadOnlySet_Unbound)) { - concreteType = _typeSymbols.HashSet; + typeToInstantiate = _typeSymbols.HashSet; populationCastType = _typeSymbols.ISet; - constructionStrategy = InitializationStrategy.ParameterizedConstructor; + instantiationStrategy = InstantiationStrategy.ParameterizedConstructor; populationStrategy = CollectionPopulationStrategy.Cast_Then_Add; } else if (IsInterfaceMatch(type, _typeSymbols.IReadOnlyList_Unbound) || IsInterfaceMatch(type, _typeSymbols.IReadOnlyCollection_Unbound)) { - concreteType = _typeSymbols.List; + typeToInstantiate = _typeSymbols.List; populationCastType = _typeSymbols.GenericICollection; - constructionStrategy = InitializationStrategy.ParameterizedConstructor; + instantiationStrategy = InstantiationStrategy.ParameterizedConstructor; populationStrategy = CollectionPopulationStrategy.Cast_Then_Add; } else @@ -564,40 +544,37 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k return null; } - Register_AsConfigWithChildren_HelperForGen_IfRequired(elementSpec); + Debug.Assert(!(populationStrategy is CollectionPopulationStrategy.Cast_Then_Add && populationCastType is null)); EnumerableSpec spec = new(type) { ElementType = elementSpec, - InitializationStrategy = constructionStrategy, + InstantiationStrategy = instantiationStrategy, PopulationStrategy = populationStrategy, - ToEnumerableMethodCall = null, + TypeToInstantiate = ConstructGenericCollectionSpecIfRequired(typeToInstantiate, elementType) as EnumerableSpec, + PopulationCastType = ConstructGenericCollectionSpecIfRequired(populationCastType, elementType) as EnumerableSpec, }; - Debug.Assert(!(populationStrategy is CollectionPopulationStrategy.Cast_Then_Add && populationCastType is null)); - spec.ConcreteType = ConstructGenericCollectionSpecIfRequired(concreteType, elementType); - spec.PopulationCastType = ConstructGenericCollectionSpecIfRequired(populationCastType, elementType); - return spec; } - private ObjectSpec? CreateObjectSpec(INamedTypeSymbol type) + private ObjectSpec? CreateObjectSpec(INamedTypeSymbol objectSymbol) { // Add spec to cache before traversing properties to avoid stack overflow. - ObjectSpec objectSpec = new(type); - _createdSpecs.Add(type, objectSpec); + ObjectSpec objectSpec = new(objectSymbol); + _createdSpecs.Add(objectSymbol, objectSpec); string typeName = objectSpec.Name; IMethodSymbol? ctor = null; - DiagnosticDescriptor? diagnosticDescriptor = null; + DiagnosticDescriptor? initDiagDescriptor = null; - if (!(type.IsAbstract || type.TypeKind is TypeKind.Interface)) + if (!(objectSymbol.IsAbstract || objectSymbol.TypeKind is TypeKind.Interface)) { IMethodSymbol? parameterlessCtor = null; IMethodSymbol? parameterizedCtor = null; bool hasMultipleParameterizedCtors = false; - foreach (IMethodSymbol candidate in type.InstanceConstructors) + foreach (IMethodSymbol candidate in objectSymbol.InstanceConstructors) { if (candidate.DeclaredAccessibility is not Accessibility.Public) { @@ -618,35 +595,36 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k } } - bool hasPublicParameterlessCtor = type.IsValueType || parameterlessCtor is not null; + bool hasPublicParameterlessCtor = objectSymbol.IsValueType || parameterlessCtor is not null; if (!hasPublicParameterlessCtor && hasMultipleParameterizedCtors) { - diagnosticDescriptor = Diagnostics.MultipleParameterizedConstructors; + initDiagDescriptor = Diagnostics.MultipleParameterizedConstructors; objectSpec.InitExceptionMessage = string.Format(Emitter.ExceptionMessages.MultipleParameterizedConstructors, typeName); } - ctor = type.IsValueType + ctor = objectSymbol.IsValueType // Roslyn ctor fetching APIs include paramerterless ctors for structs, unlike System.Reflection. ? parameterizedCtor ?? parameterlessCtor : parameterlessCtor ?? parameterizedCtor; } - objectSpec.InitializationStrategy = ctor?.Parameters.Length is 0 ? InitializationStrategy.ParameterlessConstructor : InitializationStrategy.ParameterizedConstructor; - if (ctor is null) { - diagnosticDescriptor = Diagnostics.MissingPublicInstanceConstructor; + initDiagDescriptor = Diagnostics.MissingPublicInstanceConstructor; objectSpec.InitExceptionMessage = string.Format(Emitter.ExceptionMessages.MissingPublicInstanceConstructor, typeName); } + else + { + objectSpec.InstantiationStrategy = ctor.Parameters.Length is 0 ? InstantiationStrategy.ParameterlessConstructor : InstantiationStrategy.ParameterizedConstructor; + } - if (diagnosticDescriptor is not null) + if (initDiagDescriptor is not null) { Debug.Assert(objectSpec.InitExceptionMessage is not null); - RegisterUnsupportedType(type, diagnosticDescriptor); - return objectSpec; + RegisterUnsupportedType(objectSymbol, initDiagDescriptor); } - INamedTypeSymbol current = type; + INamedTypeSymbol current = objectSymbol; while (current is not null) { ImmutableArray members = current.GetMembers(); @@ -655,12 +633,12 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k if (member is IPropertySymbol { IsIndexer: false, IsImplicitlyDeclared: false } property) { string propertyName = property.Name; - TypeSpec? propertyTypeSpec = GetOrCreateTypeSpec(property.Type); + TypeSpec propertyTypeSpec = GetOrCreateTypeSpec(property.Type); - if (propertyTypeSpec?.CanInitialize is not true) + if (propertyTypeSpec?.CanBindTo is not true) { - InvocationDiagnosticInfo propertyDiagnostic = new InvocationDiagnosticInfo(Diagnostics.PropertyNotSupported, new string[] { propertyName, type.ToDisplayString() }); - RegisterTypeDiagnostic(causingType: type, propertyDiagnostic); + InvocationDiagnosticInfo propertyDiagnostic = new InvocationDiagnosticInfo(Diagnostics.PropertyNotSupported, new string[] { propertyName, objectSymbol.ToDisplayString() }); + RegisterTypeDiagnostic(causingType: objectSymbol, propertyDiagnostic); _invocationTargetTypeDiags.Add(propertyDiagnostic); } @@ -668,8 +646,8 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k { AttributeData? attributeData = property.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, _typeSymbols.ConfigurationKeyNameAttribute)); string configKeyName = attributeData?.ConstructorArguments.FirstOrDefault().Value as string ?? propertyName; - PropertySpec spec = new(property) { Type = propertyTypeSpec, ConfigurationKeyName = configKeyName }; + objectSpec.Properties[propertyName] = spec; Register_AsConfigWithChildren_HelperForGen_IfRequired(propertyTypeSpec); } @@ -678,7 +656,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k current = current.BaseType; } - if (objectSpec.InitializationStrategy is InitializationStrategy.ParameterizedConstructor) + if (objectSpec.InstantiationStrategy is InstantiationStrategy.ParameterizedConstructor) { List missingParameters = new(); List invalidParameters = new(); @@ -714,9 +692,9 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k } else if (missingParameters.Count > 0) { - if (type.IsValueType) + if (objectSymbol.IsValueType) { - objectSpec.InitializationStrategy = InitializationStrategy.ParameterlessConstructor; + objectSpec.InstantiationStrategy = InstantiationStrategy.ParameterlessConstructor; } else { @@ -724,7 +702,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k } } - if (objectSpec.CanInitialize) + if (objectSpec.CanInstantiate) { RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.Initialize, objectSpec); } @@ -732,26 +710,25 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, ITypeSymbol k static string FormatParams(List names) => string.Join(",", names); } - Debug.Assert((objectSpec.CanInitialize && objectSpec.InitExceptionMessage is null) || - (!objectSpec.CanInitialize && objectSpec.InitExceptionMessage is not null)); - - if (objectSpec.NeedsMemberBinding) - { - RegisterTypeForBindCoreGen(objectSpec); - } + Debug.Assert((objectSpec.CanInstantiate && objectSpec.InitExceptionMessage is null) || + (!objectSpec.CanInstantiate && objectSpec.InitExceptionMessage is not null) || + (!objectSpec.CanInstantiate && (objectSymbol.IsAbstract || objectSymbol.TypeKind is TypeKind.Interface))); + TryRegisterTypeForBindCoreGen(objectSpec); return objectSpec; } - private void Register_AsConfigWithChildren_HelperForGen_IfRequired(TypeSpec type) + private bool MemberTypeIsBindable(ITypeSymbol containingTypeSymbol, ITypeSymbol memberTypeSymbol, DiagnosticDescriptor containingTypeDiagDescriptor, out TypeSpec? memberTypeSpec) { - if (type.SpecKind is TypeSpecKind.Object or - TypeSpecKind.Enumerable or - TypeSpecKind.Dictionary) + if (GetOrCreateTypeSpec(memberTypeSymbol) is TypeSpec { CanBindTo: true } spec) { - - _sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + memberTypeSpec = spec; + return true; } + + RegisterUnsupportedType(containingTypeSymbol, containingTypeDiagDescriptor); + memberTypeSpec = null; + return false; } private bool TryGetElementType(INamedTypeSymbol type, out ITypeSymbol? elementType) @@ -794,6 +771,22 @@ private bool IsCandidateDictionary(INamedTypeSymbol type, out ITypeSymbol? keyTy private bool IsCollection(ITypeSymbol type) => type is INamedTypeSymbol namedType && GetInterface(namedType, _typeSymbols.IEnumerable) is not null; + private bool IsSupportedArrayType(ITypeSymbol type) + { + if (type is not IArrayTypeSymbol arrayType) + { + return false; + } + + if (arrayType.Rank > 1) + { + RegisterUnsupportedType(arrayType, Diagnostics.MultiDimArraysNotSupported); + return false; + } + + return true; + } + private static INamedTypeSymbol? GetInterface(INamedTypeSymbol type, INamedTypeSymbol @interface) { if (IsInterfaceMatch(type, @interface)) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs similarity index 94% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs index c420097d99d6ae..c4f128cffd6c1d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using SourceGenerators; +using System.Diagnostics; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -132,24 +132,20 @@ private void EmitBindMethods_ConfigurationBinder() void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions) { - foreach (KeyValuePair> pair in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method)) + foreach ((ComplexTypeSpec type, List interceptorInfoList) in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method)) { - (TypeSpec type, List interceptorInfoList) = (pair.Key, pair.Value); - EmitBlankLineIfRequired(); _writer.WriteLine($"/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively."); EmitInterceptsLocationAnnotations(interceptorInfoList); EmitStartBlock($"public static void {Identifier.Bind}_{type.IdentifierCompatibleSubstring}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})"); - if (type.NeedsMemberBinding) + if (type.HasBindableMembers) { + Debug.Assert(!type.IsValueType); string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null"; EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); - if (!type.IsValueType) - { - EmitCheckForNullArgument_WithBlankLine(Identifier.instance, voidReturn: true); - } + EmitCheckForNullArgument_WithBlankLine(Identifier.instance, voidReturn: true); _writer.WriteLine($$""" var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.instance}}; {{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, {{binderOptionsArg}}); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs similarity index 60% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs index 089095aa472d5b..7b698544c91514 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs @@ -5,8 +5,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text.RegularExpressions; using Microsoft.CodeAnalysis; -using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { @@ -14,6 +14,10 @@ public sealed partial class ConfigurationBindingGenerator { private sealed partial class Emitter { + private int _valueSuffixIndex; + private bool _emitBlankLineBeforeNextStatement; + private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]")); + private bool ShouldEmitMethods(MethodsToGen_CoreBindingHelper methods) => (_sourceGenSpec.MethodsToGen_CoreBindingHelper & methods) != 0; private void EmitCoreBindingHelpers() @@ -82,36 +86,56 @@ private void EmitGetCoreMethod() EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); - if (effectiveType is ParsableFromStringSpec stringParsableType) + switch (effectiveType) { - _writer.WriteLine($$""" - if ({{Identifier.configuration}} is not {{Identifier.IConfigurationSection}} {{Identifier.section}}) + case ParsableFromStringSpec stringParsableType: { - throw new {{Identifier.InvalidOperationException}}(); + EmitCastToIConfigurationSection(); + EmitBindingLogic( + stringParsableType, + Expression.sectionValue, + Expression.sectionPath, + writeOnSuccess: parsedValueExpr => _writer.WriteLine($"return {parsedValueExpr};"), + checkForNullSectionValue: stringParsableType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue, + useIncrementalStringValueIdentifier: false); } - """); - - EmitBindLogicFromString( - stringParsableType, - Expression.sectionValue, - Expression.sectionPath, - writeOnSuccess: parsedValueExpr => _writer.WriteLine($"return {parsedValueExpr};"), - checkForNullSectionValue: stringParsableType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue, - useIncrementalStringValueIdentifier: false); - } - else if (!EmitInitException(effectiveType)) - { - EmitBindCoreCall(effectiveType, Identifier.instance, Identifier.configuration, InitializationKind.Declaration); - _writer.WriteLine($"return {Identifier.instance};"); + break; + case ConfigurationSectionSpec configurationSectionSpec: + { + EmitCastToIConfigurationSection(); + _writer.WriteLine($"return {Identifier.section};"); + } + break; + case ComplexTypeSpec complexType: + { + if (complexType.CanInstantiate) + { + EmitBindingLogic(complexType, Identifier.instance, Identifier.configuration, InitializationKind.Declaration); + _writer.WriteLine($"return {Identifier.instance};"); + } + else if (type is ObjectSpec { InitExceptionMessage: string exMsg }) + { + _writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{exMsg}"");"); + } + } + break; } - EmitEndBlock(); + EmitEndBlock(); // End if-check for input type. } _writer.WriteLine(); Emit_NotSupportedException_TypeNotDetectedAsInput(); EmitEndBlock(); _emitBlankLineBeforeNextStatement = true; + + void EmitCastToIConfigurationSection() => + _writer.WriteLine($$""" + if ({{Identifier.configuration}} is not {{Identifier.IConfigurationSection}} {{Identifier.section}}) + { + throw new {{Identifier.InvalidOperationException}}(); + } + """); } private void EmitGetValueCoreMethod() @@ -143,7 +167,7 @@ private void EmitGetValueCoreMethod() string conditionKindExpr = GetConditionKindExpr(ref isFirstType); EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); - EmitBindLogicFromString( + EmitBindingLogic( (ParsableFromStringSpec)type.EffectiveType, Identifier.value, Expression.sectionPath, @@ -175,18 +199,16 @@ private void EmitBindCoreMainMethod() _writer.WriteLine(); bool isFirstType = true; - foreach (TypeSpec type in targetTypes) + foreach (ComplexTypeSpec type in targetTypes) { - TypeSpec effectiveType = type.EffectiveType; + ComplexTypeSpec effectiveType = (ComplexTypeSpec)type.EffectiveType; + Debug.Assert(effectiveType.HasBindableMembers); string conditionKindExpr = GetConditionKindExpr(ref isFirstType); EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))"); - if (!EmitInitException(effectiveType)) - { - _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.instance};"); - EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None); - _writer.WriteLine($"return;"); - } + _writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.instance};"); + EmitBindingLogic(type, Identifier.temp, Identifier.configuration, InitializationKind.None); + _writer.WriteLine($"return;"); EmitEndBlock(); } @@ -202,23 +224,23 @@ private void EmitBindCoreMethods() return; } - foreach (TypeSpec type in targetTypes) + foreach (ComplexTypeSpec type in targetTypes) { - Debug.Assert(type.NeedsMemberBinding); + Debug.Assert(type.HasBindableMembers); EmitBlankLineIfRequired(); EmitBindCoreMethod(type); } } - private void EmitBindCoreMethod(TypeSpec type) + private void EmitBindCoreMethod(ComplexTypeSpec type) { string objParameterExpression = $"ref {type.DisplayString} {Identifier.instance}"; EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})"); - TypeSpec effectiveType = type.EffectiveType; + ComplexTypeSpec effectiveType = (ComplexTypeSpec)type.EffectiveType; if (effectiveType is EnumerableSpec enumerable) { - if (effectiveType.InitializationStrategy is InitializationStrategy.Array) + if (effectiveType.InstantiationStrategy is InstantiationStrategy.Array) { Debug.Assert(type == effectiveType); EmitPopulationImplForArray((EnumerableSpec)type); @@ -256,7 +278,7 @@ private void EmitInitializeMethods() private void EmitInitializeMethod(ObjectSpec type) { - Debug.Assert(type.CanInitialize); + Debug.Assert(type.CanInstantiate); List ctorParams = type.ConstructorParameters; IEnumerable initOnlyProps = type.Properties.Values.Where(prop => prop is { SetOnInit: true }); List ctorArgList = new(); @@ -283,7 +305,7 @@ private void EmitInitializeMethod(ObjectSpec type) foreach (PropertySpec property in initOnlyProps) { - if (property.ShouldBind() && property.MatchingCtorParam is null) + if (property.ShouldBindTo && property.MatchingCtorParam is null) { EmitBindImplForMember(property); } @@ -314,47 +336,47 @@ void EmitBindImplForMember(MemberSpec member) TypeSpec memberType = member.Type; bool errorOnFailedBinding = member.ErrorOnFailedBinding; - string parsedMemberIdentifierDeclarationPrefix = $"{memberType.DisplayString} {member.Name}"; - string parsedMemberIdentifier; + string parsedMemberDeclarationLhs = $"{memberType.DisplayString} {member.Name}"; + string configKeyName = member.ConfigurationKeyName; + string parsedMemberAssignmentLhsExpr; - if (memberType is ParsableFromStringSpec { StringParsableTypeKind: StringParsableTypeKind.AssignFromSectionValue }) + switch (memberType) { - parsedMemberIdentifier = parsedMemberIdentifierDeclarationPrefix; + case ParsableFromStringSpec { StringParsableTypeKind: StringParsableTypeKind.AssignFromSectionValue }: + { + if (errorOnFailedBinding) + { + string condition = $@"if ({Identifier.configuration}[""{configKeyName}""] is not {parsedMemberDeclarationLhs})"; + EmitThrowBlock(condition); + _writer.WriteLine(); + return; + } - if (errorOnFailedBinding) - { - string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.DisplayString} {member.Name})"; - EmitThrowBlock(condition); - _writer.WriteLine(); - return; - } - } - else - { - parsedMemberIdentifier = member.Name; + parsedMemberAssignmentLhsExpr = parsedMemberDeclarationLhs; + } + break; + case ConfigurationSectionSpec: + { + _writer.WriteLine($"{parsedMemberDeclarationLhs} = {GetSectionFromConfigurationExpression(configKeyName)};"); + return; + } + default: + { + string bangExpr = memberType.IsValueType ? string.Empty : "!"; + string parsedMemberIdentifierDeclaration = $"{parsedMemberDeclarationLhs} = {member.DefaultValueExpr}{bangExpr};"; - string declarationSuffix; - if (errorOnFailedBinding) - { - declarationSuffix = ";"; - } - else - { - string bangExpr = memberType.IsValueType ? string.Empty : "!"; - declarationSuffix = memberType.CanInitialize - ? $" = {member.DefaultValueExpr}{bangExpr};" - : ";"; - } + _writer.WriteLine(parsedMemberIdentifierDeclaration); + _emitBlankLineBeforeNextStatement = false; - string parsedMemberIdentifierDeclaration = $"{parsedMemberIdentifierDeclarationPrefix}{declarationSuffix}"; - _writer.WriteLine(parsedMemberIdentifierDeclaration); - _emitBlankLineBeforeNextStatement = false; + parsedMemberAssignmentLhsExpr = member.Name; + } + break; } bool canBindToMember = this.EmitBindImplForMember( member, - parsedMemberIdentifier, - sectionPathExpr: GetSectionPathFromConfigurationExpression(member.ConfigurationKeyName), + parsedMemberAssignmentLhsExpr, + sectionPathExpr: GetSectionPathFromConfigurationExpression(configKeyName), canSet: true); if (canBindToMember) @@ -607,11 +629,11 @@ private void EmitPrimitiveParseMethod(ParsableFromStringSpec type) private void EmitPopulationImplForArray(EnumerableSpec type) { - EnumerableSpec concreteType = (EnumerableSpec)type.ConcreteType; + EnumerableSpec typeToInstantiate = (EnumerableSpec)type.TypeToInstantiate; // Create list and bind elements. string tempIdentifier = GetIncrementalIdentifier(Identifier.temp); - EmitBindCoreCall(concreteType, tempIdentifier, Identifier.configuration, InitializationKind.Declaration); + EmitBindingLogic(typeToInstantiate, tempIdentifier, Identifier.configuration, InitializationKind.Declaration); // Resize array and add binded elements. _writer.WriteLine($$""" @@ -627,22 +649,32 @@ private void EmitPopulationImplForEnumerableWithAdd(EnumerableSpec type) Emit_Foreach_Section_In_ConfigChildren_StartBlock(); - TypeSpec elementType = type.ElementType; + string addExpr = $"{instanceIdentifier}.{Identifier.Add}"; - if (elementType is ParsableFromStringSpec stringParsableType) - { - EmitBindLogicFromString( - stringParsableType, - Expression.sectionValue, - Expression.sectionPath, - (parsedValueExpr) => _writer.WriteLine($"{instanceIdentifier}.{Identifier.Add}({parsedValueExpr});"), - checkForNullSectionValue: true, - useIncrementalStringValueIdentifier: false); - } - else + switch (type.ElementType) { - EmitBindCoreCall(elementType, Identifier.value, Identifier.section, InitializationKind.Declaration); - _writer.WriteLine($"{instanceIdentifier}.{Identifier.Add}({Identifier.value});"); + case ParsableFromStringSpec stringParsableType: + { + EmitBindingLogic( + stringParsableType, + Expression.sectionValue, + Expression.sectionPath, + (parsedValueExpr) => _writer.WriteLine($"{addExpr}({parsedValueExpr});"), + checkForNullSectionValue: true, + useIncrementalStringValueIdentifier: false); + } + break; + case ConfigurationSectionSpec configurationSection: + { + _writer.WriteLine($"{addExpr}({Identifier.section});"); + } + break; + case ComplexTypeSpec { CanInstantiate: true } complexType: + { + EmitBindingLogic(complexType, Identifier.value, Identifier.section, InitializationKind.Declaration); + _writer.WriteLine($"{addExpr}({Identifier.value});"); + } + break; } EmitEndBlock(); @@ -658,7 +690,7 @@ private void EmitBindCoreImplForDictionary(DictionarySpec type) TypeSpec elementType = type.ElementType; // Parse key - EmitBindLogicFromString( + EmitBindingLogic( keyType, Expression.sectionKey, Expression.sectionPath, @@ -668,63 +700,56 @@ private void EmitBindCoreImplForDictionary(DictionarySpec type) void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) { - if (elementType is ParsableFromStringSpec stringParsableElementType) - { - EmitBindLogicFromString( - stringParsableElementType, - Expression.sectionValue, - Expression.sectionPath, - writeOnSuccess: parsedValueExpr => _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {parsedValueExpr};"), - checkForNullSectionValue: true, - useIncrementalStringValueIdentifier: false); - } - else // For complex types: + switch (elementType) { - Debug.Assert(elementType.CanInitialize); - - if (keyType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue) - { - // Save value to local to avoid parsing twice - during look-up and during add. - _writer.WriteLine($"{keyType.DisplayString} {Identifier.key} = {parsedKeyExpr};"); - parsedKeyExpr = Identifier.key; - } - - bool isValueType = elementType.IsValueType; - string expressionForElementIsNotNull = $"{Identifier.element} is not null"; - string elementTypeDisplayString = elementType.DisplayString + (elementType.IsValueType ? string.Empty : "?"); - - string expressionForElementExists = $"{instanceIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})"; - string conditionToUseExistingElement = expressionForElementExists; - - // If key already exists, bind to existing element instance if not null (for ref types). - if (!isValueType) - { - conditionToUseExistingElement += $" && {expressionForElementIsNotNull}"; - } + case ParsableFromStringSpec stringParsableElementType: + { + EmitBindingLogic( + stringParsableElementType, + Expression.sectionValue, + Expression.sectionPath, + writeOnSuccess: parsedValueExpr => _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {parsedValueExpr};"), + checkForNullSectionValue: true, + useIncrementalStringValueIdentifier: false); + } + break; + case ConfigurationSectionSpec configurationSection: + { + _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {Identifier.section};"); + } + break; + case ComplexTypeSpec complexElementType: + { + Debug.Assert(complexElementType.CanInstantiate); - EmitStartBlock($"if (!({conditionToUseExistingElement}))"); - EmitObjectInit(elementType, Identifier.element, InitializationKind.SimpleAssignment, Identifier.section); - EmitEndBlock(); + if (keyType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue) + { + // Save value to local to avoid parsing twice - during look-up and during add. + _writer.WriteLine($"{keyType.DisplayString} {Identifier.key} = {parsedKeyExpr};"); + parsedKeyExpr = Identifier.key; + } - if (elementType is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor or InitializationStrategy.ToEnumerableMethod } collectionSpec) - { - // This is a read-only collection. If the element exists and is not null, - // we need to copy its contents into a new instance & then append/bind to that. + bool isValueType = complexElementType.IsValueType; + string expressionForElementIsNotNull = $"{Identifier.element} is not null"; + string elementTypeDisplayString = complexElementType.DisplayString + (complexElementType.IsValueType ? string.Empty : "?"); - string initExpression = collectionSpec.InitializationStrategy is InitializationStrategy.ParameterizedConstructor - ? $"new {collectionSpec.ConcreteType.DisplayString}({Identifier.element})" - : $"{Identifier.element}.{collectionSpec.ToEnumerableMethodCall!}"; + string expressionForElementExists = $"{instanceIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})"; + string conditionToUseExistingElement = expressionForElementExists; - _writer.WriteLine($$""" - else + // If key already exists, bind to existing element instance if not null (for ref types). + if (!isValueType) { - {{Identifier.element}} = {{initExpression}}; + conditionToUseExistingElement += $" && {expressionForElementIsNotNull}"; } - """); - } - EmitBindCoreCall(elementType, Identifier.element, Identifier.section, InitializationKind.None); - _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {Identifier.element};"); + EmitStartBlock($"if (!({conditionToUseExistingElement}))"); + EmitObjectInit(complexElementType, Identifier.element, InitializationKind.SimpleAssignment, Identifier.section); + EmitEndBlock(); + + EmitBindingLogic(complexElementType, Identifier.element, Identifier.section, InitializationKind.None); + _writer.WriteLine($"{instanceIdentifier}[{parsedKeyExpr}] = {Identifier.element};"); + } + break; } } @@ -733,7 +758,7 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr) private void EmitBindCoreImplForObject(ObjectSpec type) { - Debug.Assert(type.NeedsMemberBinding); + Debug.Assert(type.HasBindableMembers); string keyCacheFieldName = GetConfigKeyCacheFieldName(type); string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.DisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});"; @@ -741,8 +766,8 @@ private void EmitBindCoreImplForObject(ObjectSpec type) foreach (PropertySpec property in type.Properties.Values) { - bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor }; - if (property.ShouldBind() && !noSetter_And_IsReadonly) + bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InstantiationStrategy: InstantiationStrategy.ParameterizedConstructor }; + if (property.ShouldBindTo && !noSetter_And_IsReadonly) { string containingTypeRef = property.IsStatic ? type.DisplayString : Identifier.instance; EmitBindImplForMember( @@ -761,56 +786,60 @@ private bool EmitBindImplForMember( bool canSet) { TypeSpec effectiveMemberType = member.Type.EffectiveType; - - if (effectiveMemberType is ParsableFromStringSpec stringParsableType) - { - if (canSet) - { - bool checkForNullSectionValue = member is ParameterSpec - ? true - : stringParsableType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue; - - string nullBangExpr = checkForNullSectionValue ? string.Empty : "!"; - - EmitBlankLineIfRequired(); - EmitBindLogicFromString( - stringParsableType, - $@"{Identifier.configuration}[""{member.ConfigurationKeyName}""]", - sectionPathExpr, - writeOnSuccess: parsedValueExpr => _writer.WriteLine($"{memberAccessExpr} = {parsedValueExpr}{nullBangExpr};"), - checkForNullSectionValue, - useIncrementalStringValueIdentifier: true); - } - - return true; - } - string sectionParseExpr = GetSectionFromConfigurationExpression(member.ConfigurationKeyName); - EmitBlankLineIfRequired(); - - if (effectiveMemberType.SpecKind is TypeSpecKind.IConfigurationSection) + switch (effectiveMemberType) { - _writer.WriteLine($"{memberAccessExpr} = {sectionParseExpr};"); - return true; - } + case ParsableFromStringSpec stringParsableType: + { + if (canSet) + { + bool checkForNullSectionValue = member is ParameterSpec + ? true + : stringParsableType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue; + + string nullBangExpr = checkForNullSectionValue ? string.Empty : "!"; + + EmitBlankLineIfRequired(); + EmitBindingLogic( + stringParsableType, + $@"{Identifier.configuration}[""{member.ConfigurationKeyName}""]", + sectionPathExpr, + writeOnSuccess: parsedValueExpr => _writer.WriteLine($"{memberAccessExpr} = {parsedValueExpr}{nullBangExpr};"), + checkForNullSectionValue, + useIncrementalStringValueIdentifier: true); + } - string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})"; - string sectionIdentifier = GetIncrementalIdentifier(Identifier.section); + return true; + } + case ConfigurationSectionSpec: + { + if (canSet) + { + EmitBlankLineIfRequired(); + _writer.WriteLine($"{memberAccessExpr} = {sectionParseExpr};"); + } - EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})"); + return true; + } + case ComplexTypeSpec complexType: + { + string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})"; + string sectionIdentifier = GetIncrementalIdentifier(Identifier.section); - bool canInit = !EmitInitException(effectiveMemberType); - if (canInit) - { - EmitBindCoreCallForMember(member, memberAccessExpr, sectionIdentifier, canSet); - } + EmitBlankLineIfRequired(); + EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})"); + EmitBindingLogicForComplexMember(member, memberAccessExpr, sectionIdentifier, canSet); + EmitEndBlock(); - EmitEndBlock(); - return canInit; + return complexType.CanInstantiate; + } + default: + return false; + } } - private void EmitBindCoreCallForMember( + private void EmitBindingLogicForComplexMember( MemberSpec member, string memberAccessExpr, string configArgExpr, @@ -818,7 +847,7 @@ private void EmitBindCoreCallForMember( { TypeSpec memberType = member.Type; - TypeSpec effectiveMemberType = memberType.EffectiveType; + ComplexTypeSpec effectiveMemberType = (ComplexTypeSpec)memberType.EffectiveType; string tempIdentifier = GetIncrementalIdentifier(Identifier.temp); InitializationKind initKind; @@ -872,7 +901,7 @@ private void EmitBindCoreCallForMember( } }; - EmitBindCoreCall( + EmitBindingLogic( effectiveMemberType, targetObjAccessExpr, configArgExpr, @@ -880,6 +909,205 @@ private void EmitBindCoreCallForMember( writeOnSuccess); } + private void EmitBindingLogic( + ComplexTypeSpec type, + string memberAccessExpr, + string configArgExpr, + InitializationKind initKind, + Action? writeOnSuccess = null) + { + if (!type.HasBindableMembers) + { + if (initKind is not InitializationKind.None) + { + if (type.CanInstantiate) + { + EmitObjectInit(type, memberAccessExpr, initKind, configArgExpr); + } + else if (type is ObjectSpec { InitExceptionMessage: string exMsg }) + { + _writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{exMsg}"");"); + } + } + + return; + } + + string tempIdentifier = GetIncrementalIdentifier(Identifier.temp); + if (initKind is InitializationKind.AssignmentWithNullCheck) + { + Debug.Assert(!type.IsValueType); + _writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};"); + EmitBindingLogic(tempIdentifier, InitializationKind.AssignmentWithNullCheck); + } + else if (initKind is InitializationKind.None && type.IsValueType) + { + EmitBindingLogic(tempIdentifier, InitializationKind.Declaration); + _writer.WriteLine($"{memberAccessExpr} = {tempIdentifier};"); + } + else + { + EmitBindingLogic(memberAccessExpr, initKind); + } + + void EmitBindingLogic(string instanceToBindExpr, InitializationKind initKind) + { + string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {instanceToBindExpr}, {Identifier.binderOptions});"; + + if (type.CanInstantiate) + { + if (initKind is not InitializationKind.None) + { + EmitObjectInit(type, instanceToBindExpr, initKind, configArgExpr); + } + + EmitBindCoreCall(); + } + else + { + Debug.Assert(!type.IsValueType); + + if (type is ObjectSpec { InitExceptionMessage: string exMsg }) + { + _writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{exMsg}"");"); + } + else + { + EmitStartBlock($"if ({instanceToBindExpr} is not null)"); + EmitBindCoreCall(); + EmitEndBlock(); + } + } + + void EmitBindCoreCall() + { + _writer.WriteLine(bindCoreCall); + writeOnSuccess?.Invoke(instanceToBindExpr); + } + } + } + + private void EmitBindingLogic( + ParsableFromStringSpec type, + string sectionValueExpr, + string sectionPathExpr, + Action? writeOnSuccess, + bool checkForNullSectionValue, + bool useIncrementalStringValueIdentifier) + { + StringParsableTypeKind typeKind = type.StringParsableTypeKind; + Debug.Assert(typeKind is not StringParsableTypeKind.None); + + string nonNull_StringValue_Identifier = useIncrementalStringValueIdentifier ? GetIncrementalIdentifier(Identifier.value) : Identifier.value; + string stringValueToParse_Expr = checkForNullSectionValue ? nonNull_StringValue_Identifier : sectionValueExpr; + string parsedValueExpr = typeKind switch + { + StringParsableTypeKind.AssignFromSectionValue => stringValueToParse_Expr, + StringParsableTypeKind.Enum => $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})", + _ => $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})", + }; + + if (!checkForNullSectionValue) + { + InvokeWriteOnSuccess(); + } + else + { + EmitStartBlock($"if ({sectionValueExpr} is string {nonNull_StringValue_Identifier})"); + InvokeWriteOnSuccess(); + EmitEndBlock(); + } + + void InvokeWriteOnSuccess() => writeOnSuccess?.Invoke(parsedValueExpr); + } + + private bool EmitObjectInit(ComplexTypeSpec type, string memberAccessExpr, InitializationKind initKind, string configArgExpr) + { + CollectionSpec? collectionType = type as CollectionSpec; + string initExpr; + + string effectiveDisplayString = type.DisplayString; + if (collectionType is not null) + { + if (collectionType is EnumerableSpec { InstantiationStrategy: InstantiationStrategy.Array }) + { + initExpr = $"new {s_arrayBracketsRegex.Replace(effectiveDisplayString, "[0]", 1)}"; + } + else + { + effectiveDisplayString = (collectionType.TypeToInstantiate ?? collectionType).DisplayString; + initExpr = $"new {effectiveDisplayString}()"; + } + } + else if (type.InstantiationStrategy is InstantiationStrategy.ParameterlessConstructor) + { + initExpr = $"new {effectiveDisplayString}()"; + } + else + { + Debug.Assert(type.InstantiationStrategy is InstantiationStrategy.ParameterizedConstructor); + string initMethodIdentifier = GetInitalizeMethodDisplayString(((ObjectSpec)type)); + initExpr = $"{initMethodIdentifier}({configArgExpr}, {Identifier.binderOptions})"; + } + + switch (initKind) + { + case InitializationKind.Declaration: + { + Debug.Assert(!memberAccessExpr.Contains(".")); + _writer.WriteLine($"var {memberAccessExpr} = {initExpr};"); + } + break; + case InitializationKind.AssignmentWithNullCheck: + { + if (collectionType is CollectionSpec + { + InstantiationStrategy: InstantiationStrategy.ParameterizedConstructor or InstantiationStrategy.ToEnumerableMethod + }) + { + if (collectionType.InstantiationStrategy is InstantiationStrategy.ParameterizedConstructor) + { + _writer.WriteLine($"{memberAccessExpr} = {memberAccessExpr} is null ? {initExpr} : new {effectiveDisplayString}({memberAccessExpr});"); + } + else + { + Debug.Assert(collectionType is DictionarySpec); + _writer.WriteLine($"{memberAccessExpr} = {memberAccessExpr} is null ? {initExpr} : {memberAccessExpr}.ToDictionary(pair => pair.Key, pair => pair.Value);"); + } + } + else + { + _writer.WriteLine($"{memberAccessExpr} ??= {initExpr};"); + } + } + break; + case InitializationKind.SimpleAssignment: + { + _writer.WriteLine($"{memberAccessExpr} = {initExpr};"); + } + break; + default: + { + Debug.Fail($"Invaild initialization kind: {initKind}"); + } + break; + } + + return true; + } + + private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn) + { + string returnPostfix = voidReturn ? string.Empty : " null"; + _writer.WriteLine($$""" + if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}})) + { + return{{returnPostfix}}; + } + """); + _writer.WriteLine(); + } + private void EmitCollectionCastIfRequired(CollectionSpec type, out string instanceIdentifier) { instanceIdentifier = Identifier.instance; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ExceptionMessages.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ExceptionMessages.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/ExceptionMessages.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ExceptionMessages.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs similarity index 96% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs index fe59e46f73fc0b..8bac0f4f5af03d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs @@ -12,10 +12,10 @@ public sealed partial class ConfigurationBindingGenerator { private sealed partial class Emitter { - private string? _emittedExtsTargetType; - internal static readonly AssemblyName s_assemblyName = typeof(ConfigurationBindingGenerator).Assembly.GetName(); + private string? _emittedExtsTargetType; + private enum InitializationKind { None = 0, @@ -23,6 +23,7 @@ private enum InitializationKind AssignmentWithNullCheck = 2, Declaration = 3, } + private static class Expression { public const string configurationGetSection = "configuration.GetSection"; @@ -229,19 +230,6 @@ private void EmitCheckForNullArgument_WithBlankLine(string paramName, bool voidR _writer.WriteLine(); } - private bool EmitInitException(TypeSpec type) - { - Debug.Assert(type.InitializationStrategy is not InitializationStrategy.None); - - if (!type.CanInitialize) - { - _writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{type.InitExceptionMessage}"");"); - return true; - } - - return false; - } - private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}"; private static string GetInitalizeMethodDisplayString(ObjectSpec type) => diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsBuilderConfigurationExtensions.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsBuilderConfigurationExtensions.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsBuilderConfigurationExtensions.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsConfigurationServiceCollectionExtensions.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/OptionsConfigurationServiceCollectionExtensions.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsConfigurationServiceCollectionExtensions.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index f63ddec1f4b72e..92c4c04cfa67c9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -30,31 +30,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ConfigurationSectionSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ConfigurationSectionSpec.cs deleted file mode 100644 index ed1fcac7636ba7..00000000000000 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ConfigurationSectionSpec.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.CodeAnalysis; - -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration -{ - internal sealed record ConfigurationSectionSpec : TypeSpec - { - public ConfigurationSectionSpec(ITypeSymbol type) : base(type) { } - - public override TypeSpecKind SpecKind => TypeSpecKind.IConfigurationSection; - } -} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/InitializationStrategy.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/InitializationStrategy.cs deleted file mode 100644 index 866dd254e0181e..00000000000000 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/InitializationStrategy.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration -{ - internal enum InitializationStrategy - { - None = 0, - ParameterlessConstructor = 1, - ParameterizedConstructor = 2, - ToEnumerableMethod = 3, - Array = 4, - } -} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/BinderInvocation.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/BinderInvocation.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/BinderInvocation.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs similarity index 88% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs index bce30222493841..9feafd72ce7c59 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Operations; @@ -14,31 +13,29 @@ public sealed partial class ConfigurationBindingGenerator { private sealed partial class Parser { - private void RegisterMethodInvocation_ConfigurationBinder(BinderInvocation invocation) + private void ParseInvocation_ConfigurationBinder(BinderInvocation invocation) { switch (invocation.Operation.TargetMethod.Name) { case nameof(MethodsToGen_ConfigurationBinder.Bind): { - RegisterBindInvocation(invocation); + ParseBindInvocation_ConfigurationBinder(invocation); } break; case nameof(MethodsToGen_ConfigurationBinder.Get): { - RegisterGetInvocation(invocation); + ParseGetInvocation(invocation); } break; case nameof(MethodsToGen_ConfigurationBinder.GetValue): { - RegisterGetValueInvocation(invocation); + ParseGetValueInvocation(invocation); } break; - default: - return; } } - private void RegisterBindInvocation(BinderInvocation invocation) + private void ParseBindInvocation_ConfigurationBinder(BinderInvocation invocation) { IInvocationOperation operation = invocation.Operation!; ImmutableArray @params = operation.TargetMethod.Parameters; @@ -102,7 +99,7 @@ private void RegisterBindInvocation(BinderInvocation invocation) if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) { - RegisterAsInterceptor_ConfigBinder_BindMethod(overload, typeSpec, invocation.Operation); + RegisterInterceptor(overload, typeSpec, invocation.Operation); } static ITypeSymbol? ResolveType(IOperation conversionOperation) => @@ -122,7 +119,7 @@ private void RegisterBindInvocation(BinderInvocation invocation) }; } - private void RegisterGetInvocation(BinderInvocation invocation) + private void ParseGetInvocation(BinderInvocation invocation) { IInvocationOperation operation = invocation.Operation!; IMethodSymbol targetMethod = operation.TargetMethod; @@ -176,13 +173,13 @@ private void RegisterGetInvocation(BinderInvocation invocation) if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec) { - RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation); + RegisterInvocation(overload, invocation.Operation); RegisterTypeForGetCoreGen(typeSpec); } } - private void RegisterGetValueInvocation(BinderInvocation invocation) + private void ParseGetValueInvocation(BinderInvocation invocation) { IInvocationOperation operation = invocation.Operation!; IMethodSymbol targetMethod = operation.TargetMethod; @@ -245,23 +242,23 @@ private void RegisterGetValueInvocation(BinderInvocation invocation) if (IsParsableFromString(effectiveType, out _) && GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) { - RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation); + RegisterInvocation(overload, invocation.Operation); RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec); } } - private void RegisterAsInterceptor_ConfigBinder(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation) + private void RegisterInvocation(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation) { _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; - RegisterAsInterceptor(overload, operation); + RegisterInterceptor(overload, operation); } /// /// Registers generated Bind methods as interceptors. This is done differently from other root - /// methods because we need to + /// methods because we need to /// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects. /// - private void RegisterAsInterceptor_ConfigBinder_BindMethod(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation) + private void RegisterInterceptor(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation) { _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; _sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Diagnostics.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Diagnostics.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Diagnostics.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Diagnostics.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs similarity index 89% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs index 0ac57e88ed9ee5..fa0b3691ec4047 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/Extensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs @@ -28,6 +28,12 @@ public static void RegisterCacheEntry(this Dictionary> source, out ComplexTypeSpec Key, out List Value) + { + Key = (ComplexTypeSpec)source.Key; + Value = source.Value; + } + public static string ToIdentifierCompatibleSubstring(this ITypeSymbol type) { if (type is IArrayTypeSymbol arrayType) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs similarity index 77% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs index f65c67a7878b1a..9cf59a120e1fdc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs @@ -12,7 +12,7 @@ public sealed partial class ConfigurationBindingGenerator { private sealed partial class Parser { - private void RegisterMethodInvocation_OptionsBuilderExt(BinderInvocation invocation) + private void ParseInvocation_OptionsBuilderExt(BinderInvocation invocation) { IMethodSymbol targetMethod = invocation.Operation.TargetMethod; ImmutableArray @params = targetMethod.Parameters; @@ -25,20 +25,18 @@ private void RegisterMethodInvocation_OptionsBuilderExt(BinderInvocation invocat return; } - ITypeSymbol? typeSymbol = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None); // This would violate generic type constraint; any such invocation could not have been included in the initial parser. Debug.Assert(typeSymbol?.IsValueType is not true); - TypeSpec typeSpec = GetTargetTypeForRootInvocation(typeSymbol, invocation.Location); - if (typeSpec is null) + if (GetTargetTypeForRootInvocation(typeSymbol, invocation.Location) is not ComplexTypeSpec typeSpec) { return; } if (targetMethod.Name is "Bind") { - RegisterBindInvocation(invocation, typeSpec); + ParseBindInvocation_OptionsBuilderExt(invocation, typeSpec); } else if (targetMethod.Name is "BindConfiguration") { @@ -46,7 +44,7 @@ private void RegisterMethodInvocation_OptionsBuilderExt(BinderInvocation invocat } } - private void RegisterBindInvocation(BinderInvocation invocation, TypeSpec typeSpec) + private void ParseBindInvocation_OptionsBuilderExt(BinderInvocation invocation, ComplexTypeSpec typeSpec) { IInvocationOperation operation = invocation.Operation!; IMethodSymbol targetMethod = operation.TargetMethod; @@ -68,14 +66,14 @@ 3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, _ => MethodsToGen_Extensions_OptionsBuilder.None }; - if (overload is not MethodsToGen_Extensions_OptionsBuilder.None) + if (overload is not MethodsToGen_Extensions_OptionsBuilder.None && + TryRegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec)) { - RegisterAsInterceptor_OptionsBuilder(overload, operation); - RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec); + RegisterInvocation(overload, operation); } } - private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeSpec typeSpec) + private void ParseBindConfigurationInvocation(BinderInvocation invocation, ComplexTypeSpec typeSpec) { IMethodSymbol targetMethod = invocation.Operation.TargetMethod; ImmutableArray @params = targetMethod.Parameters; @@ -85,17 +83,17 @@ private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeS if (paramCount is 3 && @params[1].Type.SpecialType is SpecialType.System_String && - SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type)) + SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) && + TryRegisterTypeForBindCoreMainGen(typeSpec)) { - RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation); - RegisterTypeForBindCoreMainGen(typeSpec); + RegisterInvocation(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation); } } - private void RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation) + private void RegisterInvocation(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation) { _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload; - RegisterAsInterceptor(overload, operation); + RegisterInterceptor(overload, operation); // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource. _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs similarity index 77% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs index d89b124b0695fb..e86231f32e42ab 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -12,7 +12,7 @@ public sealed partial class ConfigurationBindingGenerator { private sealed partial class Parser { - private void RegisterMethodInvocation_ServiceCollectionExt(BinderInvocation invocation) + private void ParseInvocation_ServiceCollectionExt(BinderInvocation invocation) { IInvocationOperation operation = invocation.Operation!; IMethodSymbol targetMethod = operation.TargetMethod; @@ -72,25 +72,26 @@ @params[1].Type.SpecialType is SpecialType.System_String && ITypeSymbol? typeSymbol = targetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None); // This would violate generic type constraint; any such invocation could not have been included in the initial parser. Debug.Assert(typeSymbol?.IsValueType is not true); - TypeSpec typeSpec = GetTargetTypeForRootInvocation(typeSymbol, invocation.Location); - if (typeSpec is null) + if (GetTargetTypeForRootInvocation(typeSymbol, invocation.Location) is ComplexTypeSpec typeSpec && + TryRegisterTypeForMethodGen(overload, typeSpec)) { - return; + RegisterInterceptor(overload, operation); } - - RegisterTypeForMethodGen(overload, typeSpec); - RegisterAsInterceptor(overload, operation); } - private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec) + private bool TryRegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, ComplexTypeSpec typeSpec) { - RegisterTypeForBindCoreMainGen(typeSpec); + if (TryRegisterTypeForBindCoreMainGen(typeSpec)) + { + _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); + // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource, IConfigureOptions<>, ConfigureNamedOptions<>. + _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); + return true; + } - _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; - _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); - // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource, IConfigureOptions<>, ConfigureNamedOptions<>. - _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); + return false; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorLocationInfo.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/InterceptorLocationInfo.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorLocationInfo.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/KnownTypeSymbols.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/KnownTypeSymbols.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/MemberSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/MemberSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParameterSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/ParameterSpec.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParameterSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/ParameterSpec.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/PropertySpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs similarity index 95% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/PropertySpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs index 584e8d570b8a9f..4e9c468c4e3352 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/PropertySpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs @@ -29,6 +29,6 @@ public PropertySpec(IPropertySymbol property) : base(property) public override bool CanSet { get; } - public bool ShouldBind() => CanGet || CanSet; + public bool ShouldBindTo => CanGet || CanSet; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/MethodsToGen.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/MethodsToGen.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/MethodsToGen.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/CollectionSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs similarity index 64% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/CollectionSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs index 280ecc4c536482..f565d245cc5502 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/CollectionSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs @@ -5,25 +5,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal abstract record CollectionSpec : TypeSpec + internal abstract record CollectionSpec : ComplexTypeSpec { public CollectionSpec(ITypeSymbol type) : base(type) { } - public required TypeSpec ElementType { get; init; } - - public CollectionSpec? ConcreteType { get; set; } + public sealed override bool CanInstantiate => TypeToInstantiate?.CanInstantiate ?? InstantiationStrategy is not InstantiationStrategy.None; - public CollectionSpec? PopulationCastType { get; set; } + public required TypeSpec ElementType { get; init; } public required CollectionPopulationStrategy PopulationStrategy { get; init; } - public override bool CanInitialize => ConcreteType?.CanInitialize ?? CanInitComplexObject(); - - public override required InitializationStrategy InitializationStrategy { get; set; } + public required CollectionSpec? TypeToInstantiate { get; init; } - public required string? ToEnumerableMethodCall { get; init; } - - public sealed override bool NeedsMemberBinding => true; + public required CollectionSpec? PopulationCastType { get; init; } } internal sealed record EnumerableSpec : CollectionSpec @@ -31,6 +25,8 @@ internal sealed record EnumerableSpec : CollectionSpec public EnumerableSpec(ITypeSymbol type) : base(type) { } public override TypeSpecKind SpecKind => TypeSpecKind.Enumerable; + + public override bool HasBindableMembers => PopulationStrategy is not CollectionPopulationStrategy.Unknown && ElementType.CanBindTo; } internal sealed record DictionarySpec : CollectionSpec @@ -39,6 +35,8 @@ public DictionarySpec(INamedTypeSymbol type) : base(type) { } public override TypeSpecKind SpecKind => TypeSpecKind.Dictionary; + public override bool HasBindableMembers => PopulationStrategy is not CollectionPopulationStrategy.Unknown; + public required ParsableFromStringSpec KeyType { get; init; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs new file mode 100644 index 00000000000000..da5a5130141a53 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + internal abstract record ComplexTypeSpec : TypeSpec + { + public ComplexTypeSpec(ITypeSymbol type) : base(type) { } + + public InstantiationStrategy InstantiationStrategy { get; set; } + + public sealed override bool CanBindTo => CanInstantiate || HasBindableMembers; + + public sealed override TypeSpec EffectiveType => this; + + public abstract bool HasBindableMembers { get; } + } + + internal enum InstantiationStrategy + { + None = 0, + ParameterlessConstructor = 1, + ParameterizedConstructor = 2, + ToEnumerableMethod = 3, + Array = 4, + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/NullableSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/NullableSpec.cs similarity index 73% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/NullableSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/NullableSpec.cs index 9dcca27596e7ee..3de6d7d465ad98 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/NullableSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/NullableSpec.cs @@ -9,10 +9,11 @@ internal sealed record NullableSpec : TypeSpec { private readonly TypeSpec _underlyingType; - public NullableSpec(ITypeSymbol type, TypeSpec underlyingType) : base(type) - { - _underlyingType = underlyingType; - } + public NullableSpec(ITypeSymbol type, TypeSpec underlyingType) : base(type) => _underlyingType = underlyingType; + + public override bool CanBindTo => _underlyingType.CanBindTo; + + public override bool CanInstantiate => _underlyingType.CanInstantiate; public override TypeSpecKind SpecKind => TypeSpecKind.Nullable; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs similarity index 65% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs index 09008dde159ad8..f6978fa9cf470a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ObjectSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs @@ -8,20 +8,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record ObjectSpec : TypeSpec + internal sealed record ObjectSpec : ComplexTypeSpec { public ObjectSpec(INamedTypeSymbol type) : base(type) { } public override TypeSpecKind SpecKind => TypeSpecKind.Object; - public override InitializationStrategy InitializationStrategy { get; set; } + public override bool HasBindableMembers => Properties.Values.Any(p => p.ShouldBindTo); - public override bool CanInitialize => CanInitComplexObject(); + public override bool CanInstantiate => InstantiationStrategy is not InstantiationStrategy.None && InitExceptionMessage is null; public Dictionary Properties { get; } = new(StringComparer.OrdinalIgnoreCase); public List ConstructorParameters { get; } = new(); - public override bool NeedsMemberBinding => Properties.Values.Any(p => p.ShouldBind()); + public string? InitExceptionMessage { get; set; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs similarity index 71% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs index e19e3e61d210f3..50e488008ad68d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/ParsableFromStringSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs @@ -6,7 +6,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record ParsableFromStringSpec : TypeSpec + internal abstract record SimpleTypeSpec : TypeSpec + { + public SimpleTypeSpec(ITypeSymbol type) : base(type) { } + + public sealed override bool CanBindTo => true; + + public sealed override TypeSpec EffectiveType => this; + + public sealed override bool CanInstantiate => true; + } + + internal sealed record ConfigurationSectionSpec : SimpleTypeSpec + { + public ConfigurationSectionSpec(ITypeSymbol type) : base(type) { } + + public override TypeSpecKind SpecKind => TypeSpecKind.IConfigurationSection; + } + + internal sealed record ParsableFromStringSpec : SimpleTypeSpec { public ParsableFromStringSpec(ITypeSymbol type) : base(type) { } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs similarity index 78% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs index cf03e58e5231b1..651a40639f0ced 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/TypeSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs @@ -1,10 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using Microsoft.CodeAnalysis; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { + [DebuggerDisplay("Name={DisplayString}, Kind={SpecKind}")] internal abstract record TypeSpec { private static readonly SymbolDisplayFormat s_minimalDisplayFormat = new SymbolDisplayFormat( @@ -34,17 +36,11 @@ public TypeSpec(ITypeSymbol type) public abstract TypeSpecKind SpecKind { get; } - public virtual InitializationStrategy InitializationStrategy { get; set; } + public abstract bool CanBindTo { get; } - public virtual string? InitExceptionMessage { get; set; } + public abstract bool CanInstantiate { get; } - public virtual bool CanInitialize => true; - - public virtual bool NeedsMemberBinding { get; } - - public virtual TypeSpec EffectiveType => this; - - protected bool CanInitComplexObject() => InitializationStrategy is not InitializationStrategy.None && InitExceptionMessage is null; + public abstract TypeSpec EffectiveType { get; } } internal enum TypeSpecKind diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs index 76ed9d959e6220..e92ed061808740 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Globalization; -using System.Text.Json; using System.Linq; +using System.Net; +using System.Text.Json; using Microsoft.Extensions.Configuration; using Xunit; @@ -730,5 +732,69 @@ public record OidcProviderOptions { public string? Authority { get; set; } } + + public class AClass + { + public EndPointCollection EndPoints { get; init; } = new EndPointCollection(); + + public bool Property { get; set; } = false; + } + + public sealed class EndPointCollection : Collection, IEnumerable + { + public EndPointCollection() { } + + public void Add(string hostAndPort) + { + EndPoint? endpoint; + + if (IPAddress.TryParse(hostAndPort, out IPAddress? address)) + { + endpoint = new IPEndPoint(address, 0); + } + else + { + endpoint = new DnsEndPoint(hostAndPort, 0); + } + + Add(endpoint); + } + } + + internal abstract class AbstractBase + { + public int Value { get; set; } + } + + internal sealed class Derived : AbstractBase { } + + internal sealed class DerivedWithAnotherProp : AbstractBase + { + public int Value2 { get; set; } + } + + internal class ClassWithAbstractCtorParam + { + public AbstractBase AbstractProp { get; } + + public ClassWithAbstractCtorParam(AbstractBase abstractProp) => AbstractProp = abstractProp; + } + + internal class ClassWithOptionalAbstractCtorParam + { + public AbstractBase AbstractProp { get; } + + public ClassWithOptionalAbstractCtorParam(AbstractBase? abstractProp = null) => AbstractProp = abstractProp; + } + + internal class ClassWith_DirectlyAssignable_CtorParams + { + public IConfigurationSection MySection { get; } + public object MyObject { get; } + public string MyString { get; } + + public ClassWith_DirectlyAssignable_CtorParams(IConfigurationSection mySection, object myObject, string myString) => + (MySection, MyObject, MyString) = (mySection, myObject, myString); + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 3846145f71486a..2a6006b38a2711 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -1940,12 +1940,17 @@ public void BindRootStructIsNoOp() } """); - StructWithNestedStructs.DeeplyNested obj = new(); #pragma warning disable SYSLIB1103 + StructWithNestedStructs.DeeplyNested obj = new(); configuration.Bind(obj); -#pragma warning restore SYSLIB1103 Assert.Equal(0, obj.Int32); Assert.False(obj.Boolean); + + StructWithNestedStructs.DeeplyNested? nullableObj = new(); + configuration.Bind(nullableObj); + Assert.Equal(0, obj.Int32); + Assert.False(obj.Boolean); +#pragma warning restore SYSLIB1103 } [Fact] @@ -2023,7 +2028,7 @@ public void ComplexObj_As_Dictionary_Element() [Fact] public void ComplexObj_As_Enumerable_Element() { - var configuration = TestHelpers.GetConfigurationFromJsonString("""{ "Enumerable": [{ "Latitude": 3, "Longitude": 4 }] }""") + var configuration = TestHelpers.GetConfigurationFromJsonString("""{ "Enumerable": [{ "Latitude": 3, "Longitude": 4 }] }""") .GetSection("Enumerable"); Geolocation obj = configuration.Get>()[0]; @@ -2192,5 +2197,129 @@ public void TestNullHandling_Bind() configuration.Bind(location, _ => { }); configuration.Bind("", location); } + + [Fact] + public void TestAbstractTypeAsNestedMemberForBinding() + { + // Regression test for https://github.com/dotnet/runtime/issues/91324. + + IConfiguration configuration = new ConfigurationBuilder().AddInMemoryCollection( + new KeyValuePair[] + { + new KeyValuePair("ConfigBindRepro:EndPoints:0", "localhost"), + new KeyValuePair("ConfigBindRepro:Property", "true") + }) + .Build(); + + AClass settings = new(); + configuration.GetSection("ConfigBindRepro").Bind(settings); + + Assert.Empty(settings.EndPoints); // Need custom binding feature to map "localhost" string into Endpoint instance. + Assert.True(settings.Property); + } + + [Fact] + public static void TestGettingAbstractType() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Value"":1}"); + Assert.Throws(() => configuration.Get()); + } + + [Fact] + public static void TestBindingAbstractInstance() + { + // Regression tests for https://github.com/dotnet/runtime/issues/90974. + // We only bind members on the declared binding type, i.e. AbstractBase, even + // though the actual instances are derived types that may have their own properties. + + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{""Value"":1,""Value2"":2}"); + + AbstractBase d = new Derived(); + configuration.Bind(d); + Assert.Equal(1, d.Value); + + d = new DerivedWithAnotherProp(); + configuration.Bind(d); + Assert.Equal(1, d.Value); + +#if BUILDING_SOURCE_GENERATOR_TESTS + // Divergence from reflection impl: reflection binds using instance type, + // while src-gen can only use declared type (everything has to be known AOT). + // This could change if we add an explicit API to indicate the expected runtime type(s). + Assert.Equal(0, ((DerivedWithAnotherProp)d).Value2); +#else + Assert.Equal(2, ((DerivedWithAnotherProp)d).Value2); +#endif + } + + [Fact] + public static void TestBindingAbstractMember_AsCtorParam() + { + IConfiguration configuration = TestHelpers.GetConfigurationFromJsonString(@"{ ""AbstractProp"": {""Value"":1} }"); + Assert.Throws(configuration.Get); + Assert.Throws(configuration.Get); + } + + [Fact] + public void GetIConfigurationSection() + { + var configuration = TestHelpers.GetConfigurationFromJsonString(""" + { + "vaLue": "MyString", + } + """); + + var obj = configuration.GetSection("value").Get(); + Assert.Equal("MyString", obj.Value); + + configuration = TestHelpers.GetConfigurationFromJsonString(""" + { + "vaLue": [ "MyString", { "nested": "value" } ], + } + """); + + var list = configuration.GetSection("value").Get>(); + ValidateList(list); + + var dict = configuration.Get>>(); + Assert.Equal(1, dict.Count); + ValidateList(dict["vaLue"]); + + static void ValidateList(List list) + { + Assert.Equal(2, list.Count); + Assert.Equal("0", list[0].Key); + Assert.Equal("MyString", list[0].Value); + + Assert.Equal("1", list[1].Key); + var nestedSection = Assert.IsAssignableFrom(list[1].GetSection("nested")); + Assert.Equal("value", nestedSection.Value); + } + } + + [Fact] + public void NullableDictKeys() + { + var configuration = TestHelpers.GetConfigurationFromJsonString("""{ "1": "MyString" }"""); + var dict = configuration.Get>(); + Assert.Empty(dict); + } + + [Fact] + public void IConfigurationSectionAsCtorParam() + { + var configuration = TestHelpers.GetConfigurationFromJsonString(""" + { + "MySection": "MySection", + "MyObject": "MyObject", + "MyString": "MyString", + } + """); + + var obj = configuration.Get(); + Assert.Equal("MySection", obj.MySection.Value); + Assert.Equal("MyObject", obj.MyObject); + Assert.Equal("MyString", obj.MyString); + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt new file mode 100644 index 00000000000000..14753a4a1f8e4b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt @@ -0,0 +1,72 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 18, 16)] + public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? instance) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 23, 16)] + public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? instance, Action? configureOptions) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 28, 16)] + public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? instance) + { + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + #endregion Core binding extensions. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 7b3251e7fc85dc..c48148c74c5891 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -117,6 +117,49 @@ public class MyClass2 { } await VerifyAgainstBaselineUsingFile("Bind_Key_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } + [Fact] + public async Task Bind_CanParseTargetConfigType_FromMethodParam() + { + string source = """ + using System; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfiguration config = configurationBuilder.Build(); + + BindOptions(config, new MyClass0()); + BindOptions(config, new MyClass1(), _ => { }); + BindOptions(config, "", new MyClass2()); + } + + private static void BindOptions(IConfiguration config, MyClass0 instance) + { + config.Bind(instance); + } + + private static void BindOptions(IConfiguration config, MyClass1 instance, Action? configureOptions) + { + config.Bind(instance, configureOptions); + } + + private static void BindOptions(IConfiguration config, string path, MyClass2 instance) + { + config.Bind(path, instance); + } + + public class MyClass0 { } + public class MyClass1 { } + public class MyClass2 { } + } + """; + + await VerifyAgainstBaselineUsingFile("Bind_ParseTypeFromMethodParam.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + [Fact] public async Task Get() { @@ -622,5 +665,54 @@ await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, valida Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); }); } + + [Fact] + public async Task MinimalGenerationIfNoBindableMembers() + { + string source = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfiguration configuration = configurationBuilder.Build(); + + TypeWithNoMembers obj = new(); + configuration.Bind(obj); + + TypeWithNoMembers_Wrapper obj2 = new(); + configuration.Bind(obj2); + + List obj3 = new(); + configuration.Bind(obj3); + } + } + + public class TypeWithNoMembers + { + } + + public class TypeWithNoMembers_Wrapper + { + public TypeWithNoMembers Member { get; set; } + } + + public abstract class AbstractType_CannotInit + { + } + """; + + await VerifyAgainstBaselineUsingFile( + "EmptyConfigType.generated.txt", + source, + assessDiagnostics: (d) => + { + Assert.Equal(2, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); + }, + validateOutputCompDiags: false); + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs index d8818bcf3c1d4c..0053cb41f37020 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -145,7 +145,8 @@ private static async Task VerifyAgainstBaselineUsingFile( if (validateOutputCompDiags) { - Assert.False(outputCompilation.GetDiagnostics().Any(d => d.Severity > DiagnosticSeverity.Info)); + ImmutableArray diagnostics = outputCompilation.GetDiagnostics(); + Assert.False(diagnostics.Any(d => d.Severity > DiagnosticSeverity.Info)); } return (runResult.Results[0].Diagnostics, runResult.Results[0].GeneratedSources); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 3fddad379397ef..846e64d904d531 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -177,60 +177,7 @@ public class MyClass { } } [Fact] - public async Task BindCanParseMethodParam() - { - string source = """ - using System; - using Microsoft.AspNetCore.Builder; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - - public class Program - { - public static void Main() - { - ConfigurationBuilder configurationBuilder = new(); - IConfiguration config = configurationBuilder.Build(); - - BindOptions(config, new MyClass0()); - BindOptions(config, new MyClass1(), (_) => { }); - BindOptions(config, "", new MyClass2()); - } - - private void BindOptions(IConfiguration config, MyClass0 instance) - { - config.Bind(instance); - } - - private void BindOptions(IConfiguration config, MyClass1 instance, Action? configureOptions) - { - config.Bind(instance, configureOptions); - } - - private void BindOptions(IConfiguration config, string path, MyClass2 instance) - { - config.Bind(path, instance); - } - - public class MyClass0 { } - public class MyClass1 { } - public class MyClass2 { } - } - """; - - var (d, r) = await RunGenerator(source); - Assert.Single(r); - - string generatedSource = string.Join('\n', r[0].SourceText.Lines.Select(x => x.ToString())); - Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? instance)", generatedSource); - Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? instance, Action? configureOptions)", generatedSource); - Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? instance)", generatedSource); - - Assert.Empty(d); - } - - [Fact] - public async Task SucceedForMinimalInput() + public async Task SucceedWhenGivenMinimumRequiredReferences() { string source = """ using System; @@ -337,8 +284,8 @@ public class AnotherGraphWithUnsupportedMembers var (d, r) = await RunGenerator(source, references: GetAssemblyRefsWithAdditional(typeof(ImmutableArray<>), typeof(Encoding), typeof(JsonSerializer))); Assert.Single(r); - Assert.Equal(12, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); - Assert.Equal(10, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); + Assert.Equal(47, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); + Assert.Equal(44, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); } } } From 7b324065ebe0149e13960259c91701bc2d2ed156 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 17:44:33 -0700 Subject: [PATCH 194/345] Fix URL for syslib diagnostics (#92160) Co-authored-by: Eric StJohn --- src/libraries/Common/src/Roslyn/DiagnosticDescriptorHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/Roslyn/DiagnosticDescriptorHelper.cs b/src/libraries/Common/src/Roslyn/DiagnosticDescriptorHelper.cs index d11fdd8b5aaa03..8c5783ff9bd0b4 100644 --- a/src/libraries/Common/src/Roslyn/DiagnosticDescriptorHelper.cs +++ b/src/libraries/Common/src/Roslyn/DiagnosticDescriptorHelper.cs @@ -17,7 +17,7 @@ public static DiagnosticDescriptor Create( LocalizableString? description = null, params string[] customTags) { - string helpLink = $"https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/{id.ToLowerInvariant()}.md"; + string helpLink = $"https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/{id.ToLowerInvariant()}"; return new DiagnosticDescriptor(id, title, messageFormat, category, defaultSeverity, isEnabledByDefault, description, helpLink, customTags); } From c7252a392eee592c98ca509790fb3ed32407317e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Sep 2023 18:26:40 -0700 Subject: [PATCH 195/345] [release/8.0] Fix support of FromKeyedServicesAttribute in ActivatorUtilities.CreateFactory (#92144) * Fix support of FromKeyedServicesAttribute in ActivatorUtilities.CreateFactory * Addressing comment and adding a test --------- Co-authored-by: Benjamin Petit --- .../src/ActivatorUtilities.cs | 121 +++++++++++------- ...edDependencyInjectionSpecificationTests.cs | 36 ++++++ .../tests/DI.Tests/ActivatorUtilitiesTests.cs | 108 ++++++++++++++++ 3 files changed, 217 insertions(+), 48 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs index 6a42373ccc77d4..3ba30724d97f2b 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ActivatorUtilities.cs @@ -36,7 +36,7 @@ public static class ActivatorUtilities #endif private static readonly MethodInfo GetServiceInfo = - GetMethodInfo>((sp, t, r, c) => GetService(sp, t, r, c)); + GetMethodInfo>((sp, t, r, c, k) => GetService(sp, t, r, c, k)); /// /// Instantiate a type with constructor arguments provided directly and/or from an . @@ -324,9 +324,9 @@ private static MethodInfo GetMethodInfo(Expression expr) return mc.Method; } - private static object? GetService(IServiceProvider sp, Type type, Type requiredBy, bool hasDefaultValue) + private static object? GetService(IServiceProvider sp, Type type, Type requiredBy, bool hasDefaultValue, object? key) { - object? service = sp.GetService(type); + object? service = key == null ? sp.GetService(type) : GetKeyedService(sp, type, key); if (service is null && !hasDefaultValue) { ThrowHelperUnableToResolveService(type, requiredBy); @@ -361,10 +361,12 @@ private static BlockExpression BuildFactoryExpression( } else { + var keyAttribute = (FromKeyedServicesAttribute?) Attribute.GetCustomAttribute(constructorParameter, typeof(FromKeyedServicesAttribute), inherit: false); var parameterTypeExpression = new Expression[] { serviceProvider, Expression.Constant(parameterType, typeof(Type)), Expression.Constant(constructor.DeclaringType, typeof(Type)), - Expression.Constant(hasDefaultValue) }; + Expression.Constant(hasDefaultValue), + Expression.Constant(keyAttribute?.Key) }; constructorArguments[i] = Expression.Call(GetServiceInfo, parameterTypeExpression); } @@ -435,10 +437,10 @@ private static ObjectFactory CreateFactoryReflection( if (matchedArgCount == 0) { // All injected; use a fast path. - Type[] types = GetParameterTypes(); + FactoryParameterContext[] parameters = GetFactoryParameterContext(); return useFixedValues ? - (serviceProvider, arguments) => ReflectionFactoryServiceOnlyFixed(invoker, types, declaringType, serviceProvider) : - (serviceProvider, arguments) => ReflectionFactoryServiceOnlySpan(invoker, types, declaringType, serviceProvider); + (serviceProvider, arguments) => ReflectionFactoryServiceOnlyFixed(invoker, parameters, declaringType, serviceProvider) : + (serviceProvider, arguments) => ReflectionFactoryServiceOnlySpan(invoker, parameters, declaringType, serviceProvider); } if (matchedArgCount == constructorParameters.Length) @@ -456,16 +458,6 @@ ObjectFactory InvokeCanonical() (serviceProvider, arguments) => ReflectionFactoryCanonicalFixed(invoker, parameters, declaringType, serviceProvider, arguments) : (serviceProvider, arguments) => ReflectionFactoryCanonicalSpan(invoker, parameters, declaringType, serviceProvider, arguments); } - - Type[] GetParameterTypes() - { - Type[] types = new Type[constructorParameters.Length]; - for (int i = 0; i < constructorParameters.Length; i++) - { - types[i] = constructorParameters[i].ParameterType; - } - return types; - } #else ParameterInfo[] constructorParameters = constructor.GetParameters(); if (constructorParameters.Length == 0) @@ -484,8 +476,15 @@ FactoryParameterContext[] GetFactoryParameterContext() for (int i = 0; i < constructorParameters.Length; i++) { ParameterInfo constructorParameter = constructorParameters[i]; + FromKeyedServicesAttribute? attr = (FromKeyedServicesAttribute?) + Attribute.GetCustomAttribute(constructorParameter, typeof(FromKeyedServicesAttribute), inherit: false); bool hasDefaultValue = ParameterDefaultValue.TryGetDefaultValue(constructorParameter, out object? defaultValue); - parameters[i] = new FactoryParameterContext(constructorParameter.ParameterType, hasDefaultValue, defaultValue, parameterMap[i] ?? -1); + parameters[i] = new FactoryParameterContext( + constructorParameter.ParameterType, + hasDefaultValue, + defaultValue, + parameterMap[i] ?? -1, + attr?.Key); } return parameters; @@ -495,18 +494,20 @@ FactoryParameterContext[] GetFactoryParameterContext() private readonly struct FactoryParameterContext { - public FactoryParameterContext(Type parameterType, bool hasDefaultValue, object? defaultValue, int argumentIndex) + public FactoryParameterContext(Type parameterType, bool hasDefaultValue, object? defaultValue, int argumentIndex, object? serviceKey) { ParameterType = parameterType; HasDefaultValue = hasDefaultValue; DefaultValue = defaultValue; ArgumentIndex = argumentIndex; + ServiceKey = serviceKey; } public Type ParameterType { get; } public bool HasDefaultValue { get; } public object? DefaultValue { get; } public int ArgumentIndex { get; } + public object? ServiceKey { get; } } private static void FindApplicableConstructor( @@ -825,39 +826,39 @@ private static void ThrowMarkedCtorDoesNotTakeAllProvidedArguments() #if NET8_0_OR_GREATER // Use the faster ConstructorInvoker which also has alloc-free APIs when <= 4 parameters. private static object ReflectionFactoryServiceOnlyFixed( ConstructorInvoker invoker, - Type[] parameterTypes, + FactoryParameterContext[] parameters, Type declaringType, IServiceProvider serviceProvider) { - Debug.Assert(parameterTypes.Length >= 1 && parameterTypes.Length <= FixedArgumentThreshold); + Debug.Assert(parameters.Length >= 1 && parameters.Length <= FixedArgumentThreshold); Debug.Assert(FixedArgumentThreshold == 4); if (serviceProvider is null) ThrowHelperArgumentNullExceptionServiceProvider(); - switch (parameterTypes.Length) + switch (parameters.Length) { case 1: return invoker.Invoke( - GetService(serviceProvider, parameterTypes[0], declaringType, false)); + GetService(serviceProvider, parameters[0].ParameterType, declaringType, false, parameters[0].ServiceKey)); case 2: return invoker.Invoke( - GetService(serviceProvider, parameterTypes[0], declaringType, false), - GetService(serviceProvider, parameterTypes[1], declaringType, false)); + GetService(serviceProvider, parameters[0].ParameterType, declaringType, false, parameters[0].ServiceKey), + GetService(serviceProvider, parameters[1].ParameterType, declaringType, false, parameters[1].ServiceKey)); case 3: return invoker.Invoke( - GetService(serviceProvider, parameterTypes[0], declaringType, false), - GetService(serviceProvider, parameterTypes[1], declaringType, false), - GetService(serviceProvider, parameterTypes[2], declaringType, false)); + GetService(serviceProvider, parameters[0].ParameterType, declaringType, false, parameters[0].ServiceKey), + GetService(serviceProvider, parameters[1].ParameterType, declaringType, false, parameters[1].ServiceKey), + GetService(serviceProvider, parameters[2].ParameterType, declaringType, false, parameters[2].ServiceKey)); case 4: return invoker.Invoke( - GetService(serviceProvider, parameterTypes[0], declaringType, false), - GetService(serviceProvider, parameterTypes[1], declaringType, false), - GetService(serviceProvider, parameterTypes[2], declaringType, false), - GetService(serviceProvider, parameterTypes[3], declaringType, false)); + GetService(serviceProvider, parameters[0].ParameterType, declaringType, false, parameters[0].ServiceKey), + GetService(serviceProvider, parameters[1].ParameterType, declaringType, false, parameters[1].ServiceKey), + GetService(serviceProvider, parameters[2].ParameterType, declaringType, false, parameters[2].ServiceKey), + GetService(serviceProvider, parameters[3].ParameterType, declaringType, false, parameters[3].ServiceKey)); } return null!; @@ -865,17 +866,17 @@ private static object ReflectionFactoryServiceOnlyFixed( private static object ReflectionFactoryServiceOnlySpan( ConstructorInvoker invoker, - Type[] parameterTypes, + FactoryParameterContext[] parameters, Type declaringType, IServiceProvider serviceProvider) { if (serviceProvider is null) ThrowHelperArgumentNullExceptionServiceProvider(); - object?[] arguments = new object?[parameterTypes.Length]; - for (int i = 0; i < parameterTypes.Length; i++) + object?[] arguments = new object?[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) { - arguments[i] = GetService(serviceProvider, parameterTypes[i], declaringType, false); + arguments[i] = GetService(serviceProvider, parameters[i].ParameterType, declaringType, false, parameters[i].ServiceKey); } return invoker.Invoke(arguments.AsSpan()); @@ -907,7 +908,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter1.ParameterType, declaringType, - parameter1.HasDefaultValue)) ?? parameter1.DefaultValue); + parameter1.HasDefaultValue, + parameter1.ServiceKey)) ?? parameter1.DefaultValue); case 2: { ref FactoryParameterContext parameter2 = ref parameters[1]; @@ -920,7 +922,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter1.ParameterType, declaringType, - parameter1.HasDefaultValue)) ?? parameter1.DefaultValue, + parameter1.HasDefaultValue, + parameter1.ServiceKey)) ?? parameter1.DefaultValue, ((parameter2.ArgumentIndex != -1) // Throws a NullReferenceException if arguments is null. Consistent with expression-based factory. ? arguments![parameter2.ArgumentIndex] @@ -928,7 +931,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter2.ParameterType, declaringType, - parameter2.HasDefaultValue)) ?? parameter2.DefaultValue); + parameter2.HasDefaultValue, + parameter2.ServiceKey)) ?? parameter2.DefaultValue); } case 3: { @@ -943,7 +947,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter1.ParameterType, declaringType, - parameter1.HasDefaultValue)) ?? parameter1.DefaultValue, + parameter1.HasDefaultValue, + parameter1.ServiceKey)) ?? parameter1.DefaultValue, ((parameter2.ArgumentIndex != -1) // Throws a NullReferenceException if arguments is null. Consistent with expression-based factory. ? arguments![parameter2.ArgumentIndex] @@ -951,7 +956,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter2.ParameterType, declaringType, - parameter2.HasDefaultValue)) ?? parameter2.DefaultValue, + parameter2.HasDefaultValue, + parameter2.ServiceKey)) ?? parameter2.DefaultValue, ((parameter3.ArgumentIndex != -1) // Throws a NullReferenceException if arguments is null. Consistent with expression-based factory. ? arguments![parameter3.ArgumentIndex] @@ -959,7 +965,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter3.ParameterType, declaringType, - parameter3.HasDefaultValue)) ?? parameter3.DefaultValue); + parameter3.HasDefaultValue, + parameter3.ServiceKey)) ?? parameter3.DefaultValue); } case 4: { @@ -975,7 +982,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter1.ParameterType, declaringType, - parameter1.HasDefaultValue)) ?? parameter1.DefaultValue, + parameter1.HasDefaultValue, + parameter1.ServiceKey)) ?? parameter1.DefaultValue, ((parameter2.ArgumentIndex != -1) // Throws a NullReferenceException if arguments is null. Consistent with expression-based factory. ? arguments![parameter2.ArgumentIndex] @@ -983,7 +991,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter2.ParameterType, declaringType, - parameter2.HasDefaultValue)) ?? parameter2.DefaultValue, + parameter2.HasDefaultValue, + parameter2.ServiceKey)) ?? parameter2.DefaultValue, ((parameter3.ArgumentIndex != -1) // Throws a NullReferenceException if arguments is null. Consistent with expression-based factory. ? arguments![parameter3.ArgumentIndex] @@ -991,7 +1000,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter3.ParameterType, declaringType, - parameter3.HasDefaultValue)) ?? parameter3.DefaultValue, + parameter3.HasDefaultValue, + parameter3.ServiceKey)) ?? parameter3.DefaultValue, ((parameter4.ArgumentIndex != -1) // Throws a NullReferenceException if arguments is null. Consistent with expression-based factory. ? arguments![parameter4.ArgumentIndex] @@ -999,7 +1009,8 @@ private static object ReflectionFactoryCanonicalFixed( serviceProvider, parameter4.ParameterType, declaringType, - parameter4.HasDefaultValue)) ?? parameter4.DefaultValue); + parameter4.HasDefaultValue, + parameter4.ServiceKey)) ?? parameter4.DefaultValue); } } @@ -1028,7 +1039,8 @@ private static object ReflectionFactoryCanonicalSpan( serviceProvider, parameter.ParameterType, declaringType, - parameter.HasDefaultValue)) ?? parameter.DefaultValue; + parameter.HasDefaultValue, + parameter.ServiceKey)) ?? parameter.DefaultValue; } return invoker.Invoke(constructorArguments.AsSpan()); @@ -1078,7 +1090,8 @@ private static object ReflectionFactoryCanonical( serviceProvider, parameter.ParameterType, declaringType, - parameter.HasDefaultValue)) ?? parameter.DefaultValue; + parameter.HasDefaultValue, + parameter.ServiceKey)) ?? parameter.DefaultValue; } return constructor.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, constructorArguments, culture: null); @@ -1099,5 +1112,17 @@ public static void ClearCache(Type[]? _) } } #endif + + private static object? GetKeyedService(IServiceProvider provider, Type type, object? serviceKey) + { + ThrowHelper.ThrowIfNull(provider); + + if (provider is IKeyedServiceProvider keyedServiceProvider) + { + return keyedServiceProvider.GetKeyedService(type, serviceKey); + } + + throw new InvalidOperationException(SR.KeyedServicesNotSupported); + } } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/KeyedDependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/KeyedDependencyInjectionSpecificationTests.cs index 32112c3e5f7691..a0dc73d58f820b 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/KeyedDependencyInjectionSpecificationTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/KeyedDependencyInjectionSpecificationTests.cs @@ -476,5 +476,41 @@ public ServiceProviderAccessor(IServiceProvider serviceProvider) public IServiceProvider ServiceProvider { get; } } + + [Fact] + public void SimpleServiceKeyedResolution() + { + // Arrange + var services = new ServiceCollection(); + services.AddKeyedTransient("simple"); + services.AddKeyedTransient("another"); + services.AddTransient(); + var provider = CreateServiceProvider(services); + var sut = provider.GetService(); + + // Act + var result = sut!.GetService("simple"); + + // Assert + Assert.True(result.GetType() == typeof(SimpleService)); + } + + public class SimpleParentWithDynamicKeyedService + { + private readonly IServiceProvider _serviceProvider; + + public SimpleParentWithDynamicKeyedService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public ISimpleService GetService(string name) => _serviceProvider.GetKeyedService(name)!; + } + + public interface ISimpleService { } + + public class SimpleService : ISimpleService { } + + public class AnotherSimpleService : ISimpleService { } } } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs index dda3cafa442eb0..f6e7c2f3a8eb7c 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ActivatorUtilitiesTests.cs @@ -240,6 +240,100 @@ public void CreateFactory_CreatesFactoryMethod_5Types_5Injected() Assert.NotNull(item.Z); } + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(true)] +#if NETCOREAPP + [InlineData(false)] +#endif + public void CreateFactory_CreatesFactoryMethod_KeyedParams(bool useDynamicCode) + { + var options = new RemoteInvokeOptions(); + if (!useDynamicCode) + { + DisableDynamicCode(options); + } + + using var remoteHandle = RemoteExecutor.Invoke(static () => + { + var factory = ActivatorUtilities.CreateFactory(Type.EmptyTypes); + + var services = new ServiceCollection(); + services.AddSingleton(new A()); + services.AddKeyedSingleton("b", new B()); + services.AddKeyedSingleton("c", new C()); + using var provider = services.BuildServiceProvider(); + ClassWithAKeyedBKeyedC item = factory(provider, null); + + Assert.IsType>(factory); + Assert.NotNull(item.A); + Assert.NotNull(item.B); + Assert.NotNull(item.C); + }, options); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(true)] +#if NETCOREAPP + [InlineData(false)] +#endif + public void CreateFactory_CreatesFactoryMethod_KeyedParams_5Types(bool useDynamicCode) + { + var options = new RemoteInvokeOptions(); + if (!useDynamicCode) + { + DisableDynamicCode(options); + } + + using var remoteHandle = RemoteExecutor.Invoke(static () => + { + var factory = ActivatorUtilities.CreateFactory(Type.EmptyTypes); + + var services = new ServiceCollection(); + services.AddSingleton(new A()); + services.AddKeyedSingleton("b", new B()); + services.AddKeyedSingleton("c", new C()); + services.AddSingleton(new S()); + services.AddSingleton(new Z()); + using var provider = services.BuildServiceProvider(); + ClassWithAKeyedBKeyedCSZ item = factory(provider, null); + + Assert.IsType>(factory); + Assert.NotNull(item.A); + Assert.NotNull(item.B); + Assert.NotNull(item.C); + }, options); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData(true)] +#if NETCOREAPP + [InlineData(false)] +#endif + public void CreateFactory_CreatesFactoryMethod_KeyedParams_1Injected(bool useDynamicCode) + { + var options = new RemoteInvokeOptions(); + if (!useDynamicCode) + { + DisableDynamicCode(options); + } + + using var remoteHandle = RemoteExecutor.Invoke(static () => + { + var factory = ActivatorUtilities.CreateFactory(new Type[] { typeof(A) }); + + var services = new ServiceCollection(); + services.AddKeyedSingleton("b", new B()); + services.AddKeyedSingleton("c", new C()); + using var provider = services.BuildServiceProvider(); + ClassWithAKeyedBKeyedC item = factory(provider, new object?[] { new A() }); + + Assert.IsType>(factory); + Assert.NotNull(item.A); + Assert.NotNull(item.B); + Assert.NotNull(item.C); + }, options); + } + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [InlineData(true)] #if NETCOREAPP @@ -527,6 +621,13 @@ internal class C { } internal class S { } internal class Z { } + internal class ClassWithAKeyedBKeyedC : ClassWithABC + { + public ClassWithAKeyedBKeyedC(A a, [FromKeyedServices("b")] B b, [FromKeyedServices("c")] C c) + : base(a, b, c) + { } + } + internal class ClassWithABCS : ClassWithABC { public S S { get; } @@ -540,6 +641,13 @@ internal class ClassWithABCSZ : ClassWithABCS public ClassWithABCSZ(A a, B b, C c, S s, Z z) : base(a, b, c, s) { Z = z; } } + internal class ClassWithAKeyedBKeyedCSZ : ClassWithABCSZ + { + public ClassWithAKeyedBKeyedCSZ(A a, [FromKeyedServices("b")] B b, [FromKeyedServices("c")] C c, S s, Z z) + : base(a, b, c, s, z) + { } + } + internal class ClassWithABC_FirstConstructorWithAttribute : ClassWithABC { [ActivatorUtilitiesConstructor] From 01751138fedd6ab8a3092edcd9dde0e6aee8c1c1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:05:12 -0700 Subject: [PATCH 196/345] [release/8.0] Fix type parameter mapping logic in ILLink/ILCompiler (#92139) * Fix type parameter mapping bug in illink * Same in ILCompiler * Check dataflow of mapped type parameter * Fix test for analyzer --------- Co-authored-by: Sven Boemer --- .../Compiler/Dataflow/CompilerGeneratedState.cs | 3 +++ .../Linker.Dataflow/CompilerGeneratedState.cs | 6 ++++-- .../DataFlow/CompilerGeneratedTypes.cs | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs index 8150abeca61b1e..6a5e2ed77cdf08 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs @@ -158,8 +158,10 @@ referencedMethod.OwningType is MetadataType generatedType && break; case ILOpcode.stsfld: + case ILOpcode.ldsfld: { // Same as above, but stsfld instead of a call to the constructor + // Ldsfld may also trigger a cctor that creates a closure environment FieldDesc? field = methodBody.GetObject(reader.ReadILToken()) as FieldDesc; if (field == null) continue; @@ -417,6 +419,7 @@ void MapGeneratedTypeTypeParameters( break; case ILOpcode.stsfld: + case ILOpcode.ldsfld: { if (body.GetObject(reader.ReadILToken()) is FieldDesc { OwningType: MetadataType owningType } && compilerGeneratedType == owningType.GetTypeDefinition()) diff --git a/src/tools/illink/src/linker/Linker.Dataflow/CompilerGeneratedState.cs b/src/tools/illink/src/linker/Linker.Dataflow/CompilerGeneratedState.cs index 5f26219e22fdea..db0f9b2481f8e4 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/CompilerGeneratedState.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/CompilerGeneratedState.cs @@ -180,7 +180,8 @@ referencedMethod.DeclaringType is var generatedType && case OperandType.InlineField: { // Same as above, but stsfld instead of a call to the constructor - if (instruction.OpCode.Code is not Code.Stsfld) + // Ldsfld may also trigger a cctor that creates a closure environment + if (instruction.OpCode.Code is not (Code.Stsfld or Code.Ldsfld)) continue; FieldDefinition? field = _context.TryResolve ((FieldReference) instruction.Operand); @@ -390,7 +391,8 @@ static void MapGeneratedTypeTypeParameters ( handled = true; } break; - case Code.Stsfld: { + case Code.Stsfld: + case Code.Ldsfld: { if (instr.Operand is FieldReference { DeclaringType: GenericInstanceType typeRef } && compilerGeneratedType == context.TryResolve (typeRef)) { return typeRef; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs index c414bc252d1280..324e2cbb505f3a 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs @@ -43,6 +43,7 @@ public static void Main () CapturingLocalFunctionInsideIterator (); LambdaInsideAsync (); LocalFunctionInsideAsync (); + NestedStaticLambda.Test (); } private static void UseIterator () @@ -352,5 +353,21 @@ void LocalFunction () await Task.Delay (0); LocalFunction (); } + + class NestedStaticLambda + { + public static class Container<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> { + public static Func, Func> NestedLambda = + (Func x) => v => x(v); + } + + [ExpectedWarning ("IL2091", "T", nameof (Container), nameof (DynamicallyAccessedMemberTypes.PublicMethods), + // https://github.com/dotnet/runtime/issues/84918 + ProducedBy = Tool.Trimmer | Tool.NativeAot)] + public static void Test () + { + Container.NestedLambda ((T t) => t) (default (T)); + } + } } } From 287c10d2539d47268a1083c4d533cf84124900cf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:05:36 -0700 Subject: [PATCH 197/345] [release/8.0] [NativeAOT] Fix iOS library build by linking standard C++ library by default (#92141) * Link with standard C++ library when building a iOS library with NativeAOT * PR feedback --------- Co-authored-by: Ivan Povazan --- .../BuildIntegration/Microsoft.NETCore.Native.Unix.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index d30e7e73578eaa..1f5b2cd681095c 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -50,6 +50,8 @@ The .NET Foundation licenses this file to you under the MIT license. libeventpipe-disabled libeventpipe-enabled + + true From 3e8b479894a7d38b7b084d75bed38d70e766011c Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Sat, 16 Sep 2023 14:10:14 -0700 Subject: [PATCH 198/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2268640 (#92159) --- .../gen/Resources/xlf/Strings.de.xlf | 2 +- .../gen/Resources/xlf/Strings.es.xlf | 2 +- .../gen/Resources/xlf/Strings.fr.xlf | 2 +- .../gen/Resources/xlf/Strings.it.xlf | 2 +- .../gen/Resources/xlf/Strings.ja.xlf | 2 +- .../gen/Resources/xlf/Strings.ko.xlf | 2 +- .../gen/Resources/xlf/Strings.pl.xlf | 2 +- .../gen/Resources/xlf/Strings.ru.xlf | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf index 89583fdc312308..5f98b4d4a396f0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.de.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Für einen Binderaufruf wurde keine Bindungslogik generiert. Nicht unterstützte Eingabemuster umfassen generische Aufrufe, vorübergehende geschachtelte Objekte und das Übergeben von Typen, die nicht "public" oder "internal" sind. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf index faa309bd384637..446d2f0f7edb8f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.es.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + No se ha generado la lógica de enlace para una llamada de enlace. Entre los patrones de entrada no admitidos se incluyen las llamadas genéricas, el paso de objetos en caja y el paso de tipos que no son "públicos" o "internos". diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf index f8d4c5a5f95d32..517d8ffad0e5cc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.fr.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + La logique de liaison n’a pas été générée pour un appel de classeur. Les modèles d’entrée non pris en charge incluent les appels génériques, le passage d’objets box et les types de passage qui ne sont pas 'public' ou 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf index 54a26a381d6fd1..787d46e9e7339f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.it.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + La logica di associazione non è stata generata per una chiamata del gestore di associazione. I modelli di input non supportati includono chiamate generici, il passaggio di oggetti boxed e il passaggio di tipi non 'public' o 'internal'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf index b5f1790b0db187..57308cabd0da29 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ja.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + バインダー呼び出しのバインド ロジックが生成されませんでした。サポートされていない入力パターンには、ジェネリック呼び出し、ボックス化されたオブジェクトの受け渡し、および 'public' または 'internal' ではない型の受け渡しが含まれます。 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf index dfcbc040fe3067..e97e99e1ac7cd0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ko.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + 바인더 호출에 대한 바인딩 논리가 생성되지 않았습니다. 지원되지 않는 입력 패턴에는 제네릭 호출, boxed 개체 전달 및 'public' 또는 'internal'이 아닌 전달 형식이 포함됩니다. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf index 1834dac0e73f15..d0a4985215c6aa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pl.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Logika powiązania nie została wygenerowana dla wywołania integratora. Nieobsługiwane wzorce wejściowe obejmują ogólne wywołania, przekazywanie obiektów w pudełkach i przekazywanie typów, które nie są „publiczne” lub „wewnętrzne”. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf index 00e4d7418b5db6..c230a1edd07d1d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.ru.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Логика привязки не создана для вызова привязки. Неподдерживаемые шаблоны ввода включают общие вызовы, передачу упакованных объектов и передачу типов, не являющихся "общедоступными" или "внутренними". From a185c2a055496874bff51a79f049c261867f05ff Mon Sep 17 00:00:00 2001 From: Hong Li Date: Mon, 21 Aug 2023 11:55:01 -0700 Subject: [PATCH 199/345] Adding PACKAGE.md to System.Runtime.Caching package (#90701) * Adding PACKAGE.md to System.Runtime.Caching package * add Remarks * move PACKAGE.md to src folder * update per PR feedback * add important block --- .../System.Runtime.Caching/src/PACKAGE.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/libraries/System.Runtime.Caching/src/PACKAGE.md diff --git a/src/libraries/System.Runtime.Caching/src/PACKAGE.md b/src/libraries/System.Runtime.Caching/src/PACKAGE.md new file mode 100644 index 00000000000000..172477bb6af149 --- /dev/null +++ b/src/libraries/System.Runtime.Caching/src/PACKAGE.md @@ -0,0 +1,37 @@ +## About + +[System.Runtime.Caching](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.caching?view=dotnet-plat-ext-7.0) ([NuGet package](https://www.nuget.org/packages/System.Runtime.Caching/)) is a packaged set of simple caching API's derived from those of the same namespace available in .Net Framework since 4.0. This package is intended for use as a bridge when porting .Net Framework applications to .Net Core. + +This `System.Runtime.Caching` package can be used with any [.NET implementation](/dotnet/standard/net-standard#net-implementation-support) that targets .NET Standard 2.0 or later. For example: +* .NET Core 3.1 or later. +* .Net Framework 4.5 or later. +* .Net 5.0 or late + +[Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/[IMemoryCache](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-7.0) is recommended over `System.Runtime.Caching`/`MemoryCache` because it's better integrated into ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0). + +> > [!IMPORTANT] +> Use `System.Runtime.Caching`/`MemoryCache` as a compatibility bridge when porting code from .NET 4.x to .NET Core. + + +## Main Types + +The main types provided by this library are: + +* `System.Runtime.Caching.MemoryCache` + +## Remarks + +[MemoryCache.PhysicalMemoryLimit](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.caching.memorycache.physicalmemorylimit?view=dotnet-plat-ext-7.0) property is only supported on windows. + +## Addtional Documentation + +* [Caching in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/caching) +* [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-7.0 ) + +## Related Packages + +* [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) + +## Feedback & Contributing + +System.Runtime.Caching is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 7dc1f6febc3472958244f466329b625bf5e1572b Mon Sep 17 00:00:00 2001 From: "MSDN.WhiteKnight" <35516665+MSDN-WhiteKnight@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:44:18 +0500 Subject: [PATCH 200/345] Update Package readme guidelines with new template (#90842) * Update package readme guidelines * Fix typo --- docs/coding-guidelines/libraries-packaging.md | 42 +++++++++++++++++-- src/libraries/System.Text.Json/src/PACKAGE.md | 2 +- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/docs/coding-guidelines/libraries-packaging.md b/docs/coding-guidelines/libraries-packaging.md index 25a2894cfe9ae5..f7c926890bf8e8 100644 --- a/docs/coding-guidelines/libraries-packaging.md +++ b/docs/coding-guidelines/libraries-packaging.md @@ -55,11 +55,47 @@ Packages can include a Markdown Readme file with a short usage documentation. To The package Readme is displayed on the package details page on [NuGet gallery](https://nuget.org/). You can include the following content in it: - A description of the package purpose. +- A list of package key features +- A code example that demostrates how to use the package. - Information when package should be used. For example, if the library is included in the shared framework in .NET, but needs to be installed via NuGet on .NET Framework, it should be mentioned. -- Information on how to get started with the package. -- Links to related documentation. - A list of common entry-point types for the package, with links to their API docs under [.NET API Browser](https://learn.microsoft.com/dotnet/api/). -- A short code example that demostrates the package usage. +- Links to related documentation. +- Information about how to provide feedback on the package and contribute to it. + +Use the following Markdown template for a package Readme: + +``` +## About + + + +## Key Features + + + +## How to Use + + + +## Main Types + + + +## Additional Documentation + +* [Conceptual documentation](...) +* [API documentation](...) + +## Related Packages + + + +## Feedback & Contributing + + + +ExamplePackage is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +``` For a list of supported Markdown features, see [NuGet documentation](https://learn.microsoft.com/nuget/nuget-org/package-readme-on-nuget-org#supported-markdown-features). diff --git a/src/libraries/System.Text.Json/src/PACKAGE.md b/src/libraries/System.Text.Json/src/PACKAGE.md index 1bfcd1da44e258..7cbbec76e65b32 100644 --- a/src/libraries/System.Text.Json/src/PACKAGE.md +++ b/src/libraries/System.Text.Json/src/PACKAGE.md @@ -237,7 +237,7 @@ The main types provided by this library are: * `System.Text.Json.Nodes.JsonNode` * `System.Text.Json.Serialization.Metadata.JsonTypeInfo` -## Addtional Documentation +## Additional Documentation * [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/overview) * [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.text.json) From 5b4148d0823f3cdfbec840edbf7388e25edbd54b Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 28 Aug 2023 13:59:05 +0200 Subject: [PATCH 201/345] Add package readmes --- .../src/PACKAGE.md | 44 ++++++++++ .../Microsoft.Bcl.Cryptography/src/PACKAGE.md | 44 ++++++++++ .../Microsoft.Bcl.Numerics/src/PACKAGE.md | 44 ++++++++++ .../Microsoft.Bcl.TimeProvider/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 47 ++++++++-- .../src/PACKAGE.md | 42 ++++++++- .../src/PACKAGE.md | 65 ++++++++------ .../src/PACKAGE.md | 42 ++++++++- .../src/PACKAGE.md | 44 +++++++++- .../src/PACKAGE.md | 85 +++++++++---------- .../src/PACKAGE.md | 42 ++++++++- .../src/PACKAGE.md | 43 +++++++++- .../src/PACKAGE.md | 42 ++++++++- .../src/PACKAGE.md | 38 ++++++++- .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++-- .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../Microsoft.Extensions.Http/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ src/libraries/System.CodeDom/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 40 ++++++++- .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../System.Composition.Hosting/src/PACKAGE.md | 44 ++++++++++ .../System.Composition.Runtime/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../System.Composition/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 46 ++++++++-- src/libraries/System.Data.Odbc/src/PACKAGE.md | 44 ++++++++++ .../System.Data.OleDb/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../System.DirectoryServices/src/PACKAGE.md | 44 ++++++++++ .../System.Drawing.Common/src/PACKAGE.md | 44 ++++++++++ .../System.Formats.Cbor/src/PACKAGE.md | 44 ++++++++++ .../System.IO.Hashing/src/PACKAGE.md | 44 ++++++++++ .../System.IO.Packaging/src/PACKAGE.md | 44 ++++++++++ .../System.IO.Pipelines/src/PACKAGE.md | 44 ++++++++++ src/libraries/System.IO.Ports/src/PACKAGE.md | 44 ++++++++++ .../System.Management/src/PACKAGE.md | 44 ++++++++++ .../System.Memory.Data/src/PACKAGE.md | 44 ++++++++++ .../System.Net.Http.Json/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../System.Numerics.Tensors/src/PACKAGE.md | 44 ++++++++++ .../System.Reflection.Context/src/PACKAGE.md | 44 ++++++++++ .../System.Reflection.Metadata/src/PACKAGE.md | 48 +++++++++-- .../src/PACKAGE.md | 44 ++++++++-- .../src/PACKAGE.md | 44 ++++++++++ .../System.Runtime.Caching/src/PACKAGE.md | 31 +++++-- .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ src/libraries/System.Speech/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../System.Text.Encodings.Web/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../System.Threading.Channels/src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ .../src/PACKAGE.md | 44 ++++++++++ src/libraries/System.Threading/src/PACKAGE.md | 44 ++++++++++ .../System.Windows.Extensions/src/PACKAGE.md | 44 ++++++++++ 97 files changed, 4180 insertions(+), 127 deletions(-) create mode 100644 src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md create mode 100644 src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md create mode 100644 src/libraries/System.CodeDom/src/PACKAGE.md create mode 100644 src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md create mode 100644 src/libraries/System.ComponentModel.Composition/src/PACKAGE.md create mode 100644 src/libraries/System.Composition.AttributedModel/src/PACKAGE.md create mode 100644 src/libraries/System.Composition.Convention/src/PACKAGE.md create mode 100644 src/libraries/System.Composition.Hosting/src/PACKAGE.md create mode 100644 src/libraries/System.Composition.Runtime/src/PACKAGE.md create mode 100644 src/libraries/System.Composition.TypedParts/src/PACKAGE.md create mode 100644 src/libraries/System.Composition/src/PACKAGE.md create mode 100644 src/libraries/System.Data.Odbc/src/PACKAGE.md create mode 100644 src/libraries/System.Data.OleDb/src/PACKAGE.md create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md create mode 100644 src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md create mode 100644 src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md create mode 100644 src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md create mode 100644 src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md create mode 100644 src/libraries/System.DirectoryServices/src/PACKAGE.md create mode 100644 src/libraries/System.Drawing.Common/src/PACKAGE.md create mode 100644 src/libraries/System.Formats.Cbor/src/PACKAGE.md create mode 100644 src/libraries/System.IO.Hashing/src/PACKAGE.md create mode 100644 src/libraries/System.IO.Packaging/src/PACKAGE.md create mode 100644 src/libraries/System.IO.Pipelines/src/PACKAGE.md create mode 100644 src/libraries/System.IO.Ports/src/PACKAGE.md create mode 100644 src/libraries/System.Management/src/PACKAGE.md create mode 100644 src/libraries/System.Memory.Data/src/PACKAGE.md create mode 100644 src/libraries/System.Net.Http.Json/src/PACKAGE.md create mode 100644 src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md create mode 100644 src/libraries/System.Numerics.Tensors/src/PACKAGE.md create mode 100644 src/libraries/System.Reflection.Context/src/PACKAGE.md create mode 100644 src/libraries/System.Resources.Extensions/src/PACKAGE.md create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md create mode 100644 src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md create mode 100644 src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md create mode 100644 src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md create mode 100644 src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md create mode 100644 src/libraries/System.Security.Permissions/src/PACKAGE.md create mode 100644 src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md create mode 100644 src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md create mode 100644 src/libraries/System.Speech/src/PACKAGE.md create mode 100644 src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md create mode 100644 src/libraries/System.Text.Encodings.Web/src/PACKAGE.md create mode 100644 src/libraries/System.Threading.AccessControl/src/PACKAGE.md create mode 100644 src/libraries/System.Threading.Channels/src/PACKAGE.md create mode 100644 src/libraries/System.Threading.RateLimiting/src/PACKAGE.md create mode 100644 src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md create mode 100644 src/libraries/System.Threading/src/PACKAGE.md create mode 100644 src/libraries/System.Windows.Extensions/src/PACKAGE.md diff --git a/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md new file mode 100644 index 00000000000000..7a9788f170fb42 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Bcl.AsyncInterfaces is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md new file mode 100644 index 00000000000000..5a3a8c037bca45 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Bcl.Cryptography is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md new file mode 100644 index 00000000000000..df05c1c906d9b8 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Bcl.Numerics is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md new file mode 100644 index 00000000000000..90901aee2d59c7 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Bcl.TimeProvider is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md new file mode 100644 index 00000000000000..651e3c04c98405 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Caching.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md new file mode 100644 index 00000000000000..baa592831d4977 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Caching.Memory is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md index 9a93ad1f76eb74..fb051d69f251b2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md @@ -1,18 +1,20 @@ ## About + + Provides abstractions of key-value pair based configuration. Interfaces defined in this package are implemented by classes in [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and other configuration packages. -Commonly used types: +## Key Features + + -- [Microsoft.Extensions.Configuration.IConfiguration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfiguration) -- [Microsoft.Extensions.Configuration.IConfigurationBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationbuilder) -- [Microsoft.Extensions.Configuration.IConfigurationProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationprovider) -- [Microsoft.Extensions.Configuration.IConfigurationRoot](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationroot) -- [Microsoft.Extensions.Configuration.IConfigurationSection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationsection) +* +* +* -For more information, see the documentation: [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration). +## How to Use -## Example + The example below shows a small code sample using this library and trying out the `ConfigurationKeyName` attribute available since .NET 6: @@ -39,3 +41,32 @@ var config = new ConfigurationBuilder() var options = config.Get(); Console.WriteLine(options.NamedProperty); // returns "value for named property" ``` + +## Main Types + + + +The main types provided by this library are: + +* [`Microsoft.Extensions.Configuration.IConfiguration`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfiguration) +* [`Microsoft.Extensions.Configuration.IConfigurationBuilder`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationbuilder) +* [`Microsoft.Extensions.Configuration.IConfigurationProvider`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationprovider) +* [`Microsoft.Extensions.Configuration.IConfigurationRoot`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationroot) +* [`Microsoft.Extensions.Configuration.IConfigurationSection`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationsection) + +## Additional Documentation + + + +* [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md index ffb402bece35f0..f39973daaad6f2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md @@ -1,10 +1,21 @@ ## About + + Provides the functionality to bind an object to data in configuration providers for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to represent the configuration data as strongly-typed classes defined in the application code. To bind a configuration, use the [Microsoft.Extensions.Configuration.ConfigurationBinder.Get](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.configurationbinder.get) extension method on the `IConfiguration` object. To use this package, you also need to install a package for the [configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration#configuration-providers), for example, [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json/) for the JSON provider. -For more information, see the documentation: [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration). +## Key Features + + + +* +* +* + +## How to Use + + -## Example The following example shows how to bind a JSON configuration section to .NET objects. ```cs @@ -81,3 +92,30 @@ You can include a configuration file using a code like this in your `.csproj` fi ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.Binder is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md index 39daac6e4ec6c0..7d4c1543012d4c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md @@ -1,29 +1,44 @@ ## About + + Command line configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from the command line arguments of your application. You can use [CommandLineConfigurationExtensions.AddCommandLine](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandlineconfigurationextensions.addcommandline) extension method on `IConfigurationBuilder` to add the command line configuration provider to the configuration builder. -For more information, see the documentation: [Command-line configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#command-line-configuration-provider). - -## Example - -The following example shows how to read application configuration from the command line. You can use a command like `dotnet run --InputPath "c:\fizz" --OutputPath "c:\buzz"` to run it. - -```cs -using System; -using Microsoft.Extensions.Configuration; - -class Program -{ - static void Main(string[] args) - { - // Build a configuration object from command line - IConfiguration config = new ConfigurationBuilder() - .AddCommandLine(args) - .Build(); - - // Read configuration values - Console.WriteLine($"InputPath: {config["InputPath"]}"); - Console.WriteLine($"OutputPath: {config["OutputPath"]}"); - } -} -``` +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Command-line configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#command-line-configuration-provider) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.commandline) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.CommandLine is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md index 84d2d9412cce76..d9612166e7ecd4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md @@ -1,10 +1,21 @@ ## About + + Environment variables configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from environment variables. You can use [EnvironmentVariablesExtensions.AddEnvironmentVariables](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.environmentvariablesextensions.addenvironmentvariables) extension method on `IConfigurationBuilder` to add the environment variables configuration provider to the configuration builder. -For more information, see the documentation: [Environment variable configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider). +## Key Features + + + +* +* +* + +## How to Use + + -## Example The following example shows how to read application configuration from environment variables. ```cs @@ -26,3 +37,30 @@ class Program } } ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Environment variable configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.environmentvariables) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.EnvironmentVariables is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md index e43c909d83225c..60b2096828e8ec 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md @@ -1,9 +1,45 @@ ## About + + Provides a base class for file-based configuration providers used with [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and extension methods for configuring them. -For more information, see the documentation: +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) +* [Microsoft.Extensions.Configuration.FileConfigurationProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.fileconfigurationprovider) +* [Microsoft.Extensions.Configuration.FileConfigurationExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.fileconfigurationextensions) + +## Related Packages + + + +## Feedback & Contributing + + -- [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) -- [Microsoft.Extensions.Configuration.FileConfigurationProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.fileconfigurationprovider) -- [Microsoft.Extensions.Configuration.FileConfigurationExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.fileconfigurationextensions) +Microsoft.Extensions.Configuration.FileExtensions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md index 7322364392c600..a86dbd4757ea19 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md @@ -1,49 +1,44 @@ ## About + + INI configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from [INI files](https://en.wikipedia.org/wiki/INI_file). You can use [IniConfigurationExtensions.AddIniFile](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iniconfigurationextensions.addinifile) extension method on `IConfigurationBuilder` to add INI configuration provider to the configuration builder. -For more information, see the documentation: [INI configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#ini-configuration-provider). - -## Example -The following example shows how to read the application configuration from INI file. - -```cs -using System; -using Microsoft.Extensions.Configuration; - -class Program -{ - static void Main() - { - // Build a configuration object from INI file - IConfiguration config = new ConfigurationBuilder() - .AddIniFile("appsettings.ini") - .Build(); - - // Get a configuration section - IConfigurationSection section = config.GetSection("Settings"); - - // Read configuration values - Console.WriteLine($"Server: {section["Server"]}"); - Console.WriteLine($"Database: {section["Database"]}"); - } -} -``` - -To run this example, include an `appsettings.ini` file with the following content in your project: - -``` -[Settings] -Server=example.com -Database=Northwind -``` - -You can include a configuration file using a code like this in your `.csproj` file: - -```xml - - - Always - - -``` +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [INI configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#ini-configuration-provider) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.ini) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.Ini is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md index ae1c6355100f3a..b1b0a8fff8421c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md @@ -1,10 +1,21 @@ ## About + + JSON configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read your application's settings from a JSON file. You can use [JsonConfigurationExtensions.AddJsonFile](https://docs.microsoft.com/dotnet/api/microsoft.extensions.configuration.jsonconfigurationextensions.addjsonfile) extension method on `IConfigurationBuilder` to add the JSON configuration provider to the configuration builder. -For more information, see the documentation: [JSON configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#json-configuration-provider). +## Key Features + + + +* +* +* + +## How to Use + + -## Example The following example shows how to read application settings from the JSON configuration file. ```cs @@ -60,3 +71,30 @@ You can include a configuration file using a code like this in your `.csproj` fi ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [JSON configuration provider](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#json-configuration-provider) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.json) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.Json is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md index 4dba7ccd6bbb5d..976bf5598f60f4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md @@ -1,8 +1,45 @@ ## About + + User secrets configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). User secrets mechanism enables you to override application configuration settings with values stored in the local secrets file. You can use [UserSecretsConfigurationExtensions.AddUserSecrets](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.usersecretsconfigurationextensions.addusersecrets) extension method on `IConfigurationBuilder` to add user secrets provider to the configuration builder. -For more information, see the documentation: +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) +* [Safe storage of app secrets in development in ASP.NET Core](https://learn.microsoft.com/aspnet/core/security/app-secrets) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.usersecrets) + +## Related Packages + + + +## Feedback & Contributing + + -- [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) -- [Safe storage of app secrets in development in ASP.NET Core](https://learn.microsoft.com/aspnet/core/security/app-secrets) +Microsoft.Extensions.Configuration.UserSecrets is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md index d47be06c8dea3b..602c919514ddce 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md @@ -1,10 +1,21 @@ ## About + + XML configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from XML files. You can use [XmlConfigurationExtensions.AddXmlFile](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.xmlconfigurationextensions.addxmlfile) extension method on `IConfigurationBuilder` to add XML configuration provider to the configuration builder. -For more information, see the documentation: [XML configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#xml-configuration-provider). +## Key Features + + + +* +* +* + +## How to Use + + -## Example The following example shows how to read the application configuration from XML file. ```cs @@ -59,3 +70,30 @@ You can include a configuration file using a code like this in your `.csproj` fi ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [XML configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#xml-configuration-provider) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.xml) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration.Xml is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md index 92e93652f7a609..13f09693b243a3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md @@ -1,8 +1,44 @@ ## About + + `Microsoft.Extensions.Configuration` is combined with a core configuration abstraction under `Microsoft.Extensions.Configuration.Abstractions` that allows for building different kinds of configuration providers to retrieve key/value pair configuration values from in the form of `IConfiguration`. There are a number of built-in configuration provider implementations to read from environment variables, in-memory collections, JSON, INI or XML files. Aside from the built-in variations, there are more shipped libraries shipped by community for integration with various configuration service and other data sources. -For more information, see the documentation: +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + - [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) - [Microsoft.Extensions.Configuration namespace](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Configuration is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md new file mode 100644 index 00000000000000..9ec0653cb849c6 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.DependencyInjection.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md new file mode 100644 index 00000000000000..79b5aea01302e5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.DependencyInjection.Specification.Tests is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md new file mode 100644 index 00000000000000..dbf19733382c4d --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.DependencyInjection is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md index f4d4a485899ebb..d8bcd473f60d0a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md @@ -1,16 +1,22 @@ ## About + + Provides abstractions for reading `.deps` files. When a .NET application is compiled, the SDK generates a JSON manifest file (`.deps.json`) that contains information about application dependencies. You can use `Microsoft.Extensions.DependencyModel` to read information from this manifest at run time. This is useful when you want to dynamically compile code (for example, using Roslyn Emit API) referencing the same dependencies as your main application. By default, the dependency manifest contains information about the application's target framework and runtime dependencies. Set the [PreserveCompilationContext](https://docs.microsoft.com/dotnet/core/project-sdk/msbuild-props#preservecompilationcontext) project property to `true` to additionally include information about reference assemblies used during compilation. -For more information, see the documentation: +## Key Features + + -- [.deps.json file format](https://github.com/dotnet/sdk/blob/main/documentation/specs/runtime-configuration-file.md#appnamedepsjson) -- [Microsoft.Extensions.DependencyModel namespace](https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencymodel) -- [Microsoft.Extensions.DependencyModel.DependencyContext](https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencymodel.dependencycontext) +* +* +* -## Example +## How to Use + + The following example shows how to display the list of assemblies used when compiling the current application. Include `true` in your project file to run this example. @@ -35,3 +41,31 @@ class Program } } ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [.deps.json file format](https://github.com/dotnet/sdk/blob/main/documentation/specs/runtime-configuration-file.md#appnamedepsjson) +* [Microsoft.Extensions.DependencyModel namespace](https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencymodel) +* [Microsoft.Extensions.DependencyModel.DependencyContext](https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencymodel.dependencycontext) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.DependencyModel is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md new file mode 100644 index 00000000000000..efb7ca7c9133cc --- /dev/null +++ b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.FileProviders.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md new file mode 100644 index 00000000000000..122fbecfa2ba91 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.FileProviders.Composite is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md new file mode 100644 index 00000000000000..bf3378a56e63dd --- /dev/null +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.FileProviders.Physical is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md new file mode 100644 index 00000000000000..a5d26b28318fda --- /dev/null +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.FileSystemGlobbing is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md new file mode 100644 index 00000000000000..b94327b9a0078f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Hosting.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md new file mode 100644 index 00000000000000..ffb5501c8568fe --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Hosting.Systemd is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md new file mode 100644 index 00000000000000..e70b7da4ac046f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Hosting.WindowsServices is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md new file mode 100644 index 00000000000000..4370cde8aa3573 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Hosting is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md new file mode 100644 index 00000000000000..7effd1dfd486cf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Http is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md new file mode 100644 index 00000000000000..534ef37b23d3b0 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md new file mode 100644 index 00000000000000..7c38fc44d350f7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.Configuration is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md new file mode 100644 index 00000000000000..582bba45f12169 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.Console is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md new file mode 100644 index 00000000000000..b933164215cb84 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.Debug is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md new file mode 100644 index 00000000000000..9f1330aad75f6a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.EventLog is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md new file mode 100644 index 00000000000000..8a67a2888f46db --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.EventSource is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md new file mode 100644 index 00000000000000..7bab863fa95cc9 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging.TraceSource is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md new file mode 100644 index 00000000000000..302b93b4956421 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Logging is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md new file mode 100644 index 00000000000000..1609a20ac51d7b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Options.ConfigurationExtensions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md new file mode 100644 index 00000000000000..3bf3280ad4cf1b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Options.DataAnnotations is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md new file mode 100644 index 00000000000000..220873bc79027f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Options is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md new file mode 100644 index 00000000000000..db0a84ec52694c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +Microsoft.Extensions.Primitives is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md b/src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md b/src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md b/src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md b/src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.CodeDom/src/PACKAGE.md b/src/libraries/System.CodeDom/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.CodeDom/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Collections.Immutable/src/PACKAGE.md b/src/libraries/System.Collections.Immutable/src/PACKAGE.md index cf4995b4cad9ca..1b39d42bb175f0 100644 --- a/src/libraries/System.Collections.Immutable/src/PACKAGE.md +++ b/src/libraries/System.Collections.Immutable/src/PACKAGE.md @@ -1,10 +1,46 @@ ## About + + This package provides collections that are thread safe and guaranteed to never change their contents, also known as immutable collections. Like strings, any methods that perform modifications will not change the existing instance but instead return a new instance. For efficiency reasons, the implementation uses a sharing mechanism to ensure that newly created instances share as much data as possible with the previous instance while ensuring that operations have a predictable time complexity. The `System.Collections.Immutable` library is built-in as part of the shared framework in .NET Runtime. The package can be installed when you need to use it in other target frameworks. -For more information, see the documentation: +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + - [Collections and Data Structures](https://docs.microsoft.com/dotnet/standard/collections/) -- [System.Collections.Immutable API reference](https://docs.microsoft.com/dotnet/api/system.collections.immutable) +- [API documentation](https://docs.microsoft.com/dotnet/api/system.collections.immutable) + +## Related Packages + + + +## Feedback & Contributing + + + +System.Collections.Immutable is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md b/src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.Composition/src/PACKAGE.md b/src/libraries/System.ComponentModel.Composition/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.ComponentModel.Composition/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.AttributedModel/src/PACKAGE.md b/src/libraries/System.Composition.AttributedModel/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Composition.AttributedModel/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.Convention/src/PACKAGE.md b/src/libraries/System.Composition.Convention/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Composition.Convention/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.Hosting/src/PACKAGE.md b/src/libraries/System.Composition.Hosting/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Composition.Hosting/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.Runtime/src/PACKAGE.md b/src/libraries/System.Composition.Runtime/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Composition.Runtime/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.TypedParts/src/PACKAGE.md b/src/libraries/System.Composition.TypedParts/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Composition.TypedParts/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition/src/PACKAGE.md b/src/libraries/System.Composition/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Composition/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md b/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md index 8448be2423b11b..fdaea06fddb7e3 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md +++ b/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md @@ -1,15 +1,20 @@ ## About + + Provides types that support using XML configuration files (`app.config`). This package exists only to support migrating existing .NET Framework code that already uses System.Configuration. When writing new code, use another configuration system instead, such as [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). -For more information, see the documentation: +## Key Features + + -- [Configure apps by using configuration files](https://docs.microsoft.com/dotnet/framework/configure-apps/) -- [System.Configuration namespace](https://docs.microsoft.com/dotnet/api/system.configuration) -- [System.Configuration.Configuration](https://docs.microsoft.com/dotnet/api/system.configuration.configuration) -- [System.Configuration.ConfigurationManager](https://docs.microsoft.com/dotnet/api/system.configuration.configurationmanager) +* +* +* -## Example +## How to Use + + The following example shows how to read and modify the application configuration settings. @@ -63,3 +68,32 @@ To run this example, include an `app.config` file with the following content in ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Configure apps by using configuration files](https://docs.microsoft.com/dotnet/framework/configure-apps/) +* [System.Configuration namespace](https://docs.microsoft.com/dotnet/api/system.configuration) +* [System.Configuration.Configuration](https://docs.microsoft.com/dotnet/api/system.configuration.configuration) +* [System.Configuration.ConfigurationManager](https://docs.microsoft.com/dotnet/api/system.configuration.configurationmanager) + +## Related Packages + + + +## Feedback & Contributing + + + +System.Configuration.ConfigurationManager is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md b/src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md b/src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices/src/PACKAGE.md b/src/libraries/System.DirectoryServices/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.DirectoryServices/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Drawing.Common/src/PACKAGE.md b/src/libraries/System.Drawing.Common/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Formats.Cbor/src/PACKAGE.md b/src/libraries/System.Formats.Cbor/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Formats.Cbor/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Hashing/src/PACKAGE.md b/src/libraries/System.IO.Hashing/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.IO.Hashing/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Packaging/src/PACKAGE.md b/src/libraries/System.IO.Packaging/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.IO.Packaging/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Pipelines/src/PACKAGE.md b/src/libraries/System.IO.Pipelines/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.IO.Pipelines/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Ports/src/PACKAGE.md b/src/libraries/System.IO.Ports/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.IO.Ports/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Management/src/PACKAGE.md b/src/libraries/System.Management/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Management/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Memory.Data/src/PACKAGE.md b/src/libraries/System.Memory.Data/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Memory.Data/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Net.Http.Json/src/PACKAGE.md b/src/libraries/System.Net.Http.Json/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Net.Http.Json/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/src/PACKAGE.md b/src/libraries/System.Numerics.Tensors/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Reflection.Context/src/PACKAGE.md b/src/libraries/System.Reflection.Context/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Reflection.Context/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Reflection.Metadata/src/PACKAGE.md b/src/libraries/System.Reflection.Metadata/src/PACKAGE.md index 43543a703a9123..42ee1764292807 100644 --- a/src/libraries/System.Reflection.Metadata/src/PACKAGE.md +++ b/src/libraries/System.Reflection.Metadata/src/PACKAGE.md @@ -1,18 +1,22 @@ ## About + + This package provides a low-level .NET (ECMA-335) metadata reader and writer. It's geared for performance and is the ideal choice for building higher-level libraries that intend to provide their own object model, such as compilers. The metadata format is defined by the [ECMA-335 - Common Language Infrastructure (CLI)](http://www.ecma-international.org/publications/standards/Ecma-335.htm) specification and [its amendments](https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md). The `System.Reflection.Metadata` library is included in the .NET Runtime shared framework. The package can be installed when you need to use it in other target frameworks. -For more information, see the documentation: +## Key Features + + -- [System.Reflection.Metadata.MetadataReader](https://docs.microsoft.com/dotnet/api/system.reflection.metadata.metadatareader) -- [System.Reflection.PortableExecutable.PEReader](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.pereader) -- [System.Reflection.Metadata.Ecma335.MetadataBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.metadata.ecma335.metadatabuilder) -- [System.Reflection.PortableExecutable.PEBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.pebuilder) -- [System.Reflection.PortableExecutable.ManagedPEBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.managedpebuilder) +* +* +* -## Example +## How to Use + + The following example shows how to read assembly information using PEReader and MetadataReader. @@ -80,3 +84,33 @@ class Program } ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [System.Reflection.Metadata.MetadataReader](https://docs.microsoft.com/dotnet/api/system.reflection.metadata.metadatareader) +* [System.Reflection.PortableExecutable.PEReader](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.pereader) +* [System.Reflection.Metadata.Ecma335.MetadataBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.metadata.ecma335.metadatabuilder) +* [System.Reflection.PortableExecutable.PEBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.pebuilder) +* [System.Reflection.PortableExecutable.ManagedPEBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.managedpebuilder) + +## Related Packages + + + +## Feedback & Contributing + + + +System.Reflection.Metadata is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md b/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md index 7e351acc94fe75..1f0e974b2bab60 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md @@ -1,14 +1,20 @@ ## About + + Provides read-only reflection on assemblies in an isolated context with support for assemblies that target different processor architectures and runtimes. Using MetadataLoadContext enables you to inspect assemblies without loading them into the main execution context. Assemblies in MetadataLoadContext are treated only as metadata, that is, you can read information about their members, but cannot execute any code contained in them. -For more information, see the documentation: +## Key Features + + -- [How to: Inspect assembly contents using MetadataLoadContext](https://docs.microsoft.com/dotnet/standard/assembly/inspect-contents-using-metadataloadcontext) -- [System.Reflection.MetadataLoadContext](https://docs.microsoft.com/dotnet/api/system.reflection.metadataloadcontext) -- [System.Reflection.MetadataAssemblyResolver](https://docs.microsoft.com/dotnet/api/system.reflection.metadataassemblyresolver) +* +* +* -## Example +## How to Use + + The following example shows how to print the list of types defined in an assembly. @@ -38,3 +44,31 @@ class Program } } ``` + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [How to: Inspect assembly contents using MetadataLoadContext](https://docs.microsoft.com/dotnet/standard/assembly/inspect-contents-using-metadataloadcontext) +* [System.Reflection.MetadataLoadContext](https://docs.microsoft.com/dotnet/api/system.reflection.metadataloadcontext) +* [System.Reflection.MetadataAssemblyResolver](https://docs.microsoft.com/dotnet/api/system.reflection.metadataassemblyresolver) + +## Related Packages + + + +## Feedback & Contributing + + + +System.Reflection.MetadataLoadContext is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Resources.Extensions/src/PACKAGE.md b/src/libraries/System.Resources.Extensions/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Resources.Extensions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Runtime.Caching/src/PACKAGE.md b/src/libraries/System.Runtime.Caching/src/PACKAGE.md index 172477bb6af149..56b8069b131681 100644 --- a/src/libraries/System.Runtime.Caching/src/PACKAGE.md +++ b/src/libraries/System.Runtime.Caching/src/PACKAGE.md @@ -1,11 +1,8 @@ ## About -[System.Runtime.Caching](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.caching?view=dotnet-plat-ext-7.0) ([NuGet package](https://www.nuget.org/packages/System.Runtime.Caching/)) is a packaged set of simple caching API's derived from those of the same namespace available in .Net Framework since 4.0. This package is intended for use as a bridge when porting .Net Framework applications to .Net Core. + -This `System.Runtime.Caching` package can be used with any [.NET implementation](/dotnet/standard/net-standard#net-implementation-support) that targets .NET Standard 2.0 or later. For example: -* .NET Core 3.1 or later. -* .Net Framework 4.5 or later. -* .Net 5.0 or late +Packaged set of simple caching API's derived from those of the same namespace available in .NET Framework since 4.0. This package is intended for use as a bridge when porting .NET Framework applications to .NET. [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/[IMemoryCache](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-7.0) is recommended over `System.Runtime.Caching`/`MemoryCache` because it's better integrated into ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0). @@ -13,25 +10,43 @@ This `System.Runtime.Caching` package can be used with any [.NET implementation] > Use `System.Runtime.Caching`/`MemoryCache` as a compatibility bridge when porting code from .NET 4.x to .NET Core. +## Key Features + + + +* +* +* + +## How to Use + + + ## Main Types + + The main types provided by this library are: * `System.Runtime.Caching.MemoryCache` -## Remarks +## Additional Documentation -[MemoryCache.PhysicalMemoryLimit](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.caching.memorycache.physicalmemorylimit?view=dotnet-plat-ext-7.0) property is only supported on windows. + -## Addtional Documentation +[MemoryCache.PhysicalMemoryLimit](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.caching.memorycache.physicalmemorylimit?view=dotnet-plat-ext-7.0) property is only supported on windows. * [Caching in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/caching) * [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-7.0 ) ## Related Packages + + * [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/) ## Feedback & Contributing + + System.Runtime.Caching is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md b/src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Permissions/src/PACKAGE.md b/src/libraries/System.Security.Permissions/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Security.Permissions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md b/src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md b/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md b/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Text.Encodings.Web/src/PACKAGE.md b/src/libraries/System.Text.Encodings.Web/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Text.Encodings.Web/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.AccessControl/src/PACKAGE.md b/src/libraries/System.Threading.AccessControl/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Threading.AccessControl/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.Channels/src/PACKAGE.md b/src/libraries/System.Threading.Channels/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Threading.Channels/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.RateLimiting/src/PACKAGE.md b/src/libraries/System.Threading.RateLimiting/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Threading.RateLimiting/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md b/src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading/src/PACKAGE.md b/src/libraries/System.Threading/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Threading/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Windows.Extensions/src/PACKAGE.md b/src/libraries/System.Windows.Extensions/src/PACKAGE.md new file mode 100644 index 00000000000000..2709a6e84e284f --- /dev/null +++ b/src/libraries/System.Windows.Extensions/src/PACKAGE.md @@ -0,0 +1,44 @@ +## About + + + + + +## Key Features + + + +* +* +* + +## How to Use + + + +## Main Types + + + +The main types provided by this library are: + +* `` +* `` +* `` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) + +## Related Packages + + + +## Feedback & Contributing + + + +**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 66d76142b246f70699eecc44b237438aad32f381 Mon Sep 17 00:00:00 2001 From: carlossanlop <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 31 Aug 2023 19:06:26 -0700 Subject: [PATCH 202/345] System.Diagnostics.EventLog --- .../src/PACKAGE.md | 95 +++++++++++++++++-- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md index 2709a6e84e284f..1cb7eae3a470b3 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md @@ -2,43 +2,120 @@ +When an error occurs in a Windows machine, the system administrator or support representative must determine what caused the error, attempt to recover any lost data, and prevent the error from recurring. It is helpful if applications, the operating system, and other system services record important events, such as low-memory conditions or excessive attempts to access a disk. The system administrator can then use the Windows Event Log to help determine what conditions caused the error and identify the context in which it occurred. +This package provides the `System.Diagnostics.EventLog.dll` assembly, which contains types that allow applications to interact with the Windows Event Log service. ## Key Features -* -* -* +* Allows reading from existing logs. +* Allows writing entries to logs. +* Can create or delete event sources. +* Can delete logs. +* Can respond to log entries. +* Can create new logs when creating an event source. ## How to Use +```cs +if(!EventLog.SourceExists("MySource")) +{ + // An event log source should not be created and immediately used. + // There is a latency time to enable the source, it should be created + // prior to executing the application that uses the source. + // Execute this sample a second time to use the new source. + EventLog.CreateEventSource("MySource", "MyNewLog"); + Console.WriteLine("Event source created. Exiting, execute the application a second time to use the source."); + // The source is created. Exit the application to allow it to be registered. + return; +} + +EventLog myLog = new(); +myLog.Source = "MySource"; +myLog.WriteEntry("Writing an informational entry to the event log."); +``` + +Notes: + +- This assembly is only supported on Windows operating systems. +- Starting with Windows Vista, you must run the application as an administrator to interact with the Windows Event Log service using the `System.Diagnostics.EventLog` class. + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace: + +- [`System.Diagnostics.EntryWrittenEventArgs`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EntryWrittenEventArgs) +- [`System.Diagnostics.EntryWrittenEventHandler`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EntryWrittenEventHandler) +- [`System.Diagnostics.EventInstance`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventInstance) +- [`System.Diagnostics.EventLog`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLog) +- [`System.Diagnostics.EventLogEntry`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntry) +- [`System.Diagnostics.EventLogEntryCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntryCollection) +- [`System.Diagnostics.EventLogEntryType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntryType) +- [`System.Diagnostics.EventLogTraceListener`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogTraceListener) +- [`System.Diagnostics.EventSourceCreationData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventSourceCreationData) +- [`System.Diagnostics.OverflowAction`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.OverflowAction) + +Under the[`System.Diagnostics.Eventing.Reader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader) namespace: + +- [`System.Diagnostics.Eventing.Reader.EventBookmark`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventBookmark) +- [`System.Diagnostics.Eventing.Reader.EventKeyword`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventKeyword) +- [`System.Diagnostics.Eventing.Reader.EventLevel`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLevel) +- [`System.Diagnostics.Eventing.Reader.EventLogConfiguration`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogConfiguration) +- [`System.Diagnostics.Eventing.Reader.EventLogException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogException) +- [`System.Diagnostics.Eventing.Reader.EventLogInformation`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogInformation) +- [`System.Diagnostics.Eventing.Reader.EventLogInvalidDataException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogInvalidDataException) +- [`System.Diagnostics.Eventing.Reader.EventLogIsolation`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogIsolation) +- [`System.Diagnostics.Eventing.Reader.EventLogLink`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogLink) +- [`System.Diagnostics.Eventing.Reader.EventLogMode`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogMode) +- [`System.Diagnostics.Eventing.Reader.EventLogNotFoundException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogNotFoundException) +- [`System.Diagnostics.Eventing.Reader.EventLogPropertySelector`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogPropertySelector) +- [`System.Diagnostics.Eventing.Reader.EventLogProviderDisabledException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogProviderDisabledException) +- [`System.Diagnostics.Eventing.Reader.EventLogQuery`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogQuery) +- [`System.Diagnostics.Eventing.Reader.EventLogReader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogReader) +- [`System.Diagnostics.Eventing.Reader.EventLogReadingException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogReadingException) +- [`System.Diagnostics.Eventing.Reader.EventLogRecord`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogRecord) +- [`System.Diagnostics.Eventing.Reader.EventLogSession`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogSession) +- [`System.Diagnostics.Eventing.Reader.EventLogStatus`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogStatus) +- [`System.Diagnostics.Eventing.Reader.EventLogType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogType) +- [`System.Diagnostics.Eventing.Reader.EventLogWatcher`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogWatcher) +- [`System.Diagnostics.Eventing.Reader.EventMetadata`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventMetadata) +- [`System.Diagnostics.Eventing.Reader.EventOpcode`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventOpcode) +- [`System.Diagnostics.Eventing.Reader.EventProperty`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventProperty) +- [`System.Diagnostics.Eventing.Reader.EventRecord`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventRecord) +- [`System.Diagnostics.Eventing.Reader.EventRecordWrittenEventArgs`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventRecordWrittenEventArgs) +- [`System.Diagnostics.Eventing.Reader.EventTask`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventTask) +- [`System.Diagnostics.Eventing.Reader.PathType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.PathType) +- [`System.Diagnostics.Eventing.Reader.ProviderMetadata`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.ProviderMetadata) +- [`System.Diagnostics.Eventing.Reader.SessionAuthentication`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.SessionAuthentication) +- [`System.Diagnostics.Eventing.Reader.StandardEventKeywords`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventKeywords) +- [`System.Diagnostics.Eventing.Reader.StandardEventLevel`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventLevel) +- [`System.Diagnostics.Eventing.Reader.StandardEventOpcode`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventOpcode) +- [`System.Diagnostics.Eventing.Reader.StandardEventTask`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventTask) ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +- [Microsoft Learn - System.Diagnostics.EventLog API reference](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLog) +- [Windows App Development - Event logging](https://learn.microsoft.com/en-us/windows/win32/eventlog/event-logging) +- [GitHub - Source code](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Diagnostics.EventLog) ## Related Packages +- [System.Diagnostics.PerformanceCounter](https://www.nuget.org/packages/System.Diagnostics.PerformanceCounter) + ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Diagnostics.EventLog** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 3b1268dc46b57d137b85823eea36cf31e963e06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:25:06 -0700 Subject: [PATCH 203/345] System.Diagnostics.PerformanceCounter --- .../src/PACKAGE.md | 211 +++++++++++++++++- 1 file changed, 202 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md index 2709a6e84e284f..1fecb16e569611 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md @@ -2,43 +2,236 @@ +Windows allows you to examine how programs you run affect your computer's performance, both in real time and by collecting log data for later analysis. You can do this via the Windows Performance Monitor tool, which uses performance counters, among other features. +Windows performance counters provide a high-level abstraction layer that provides a consistent interface for collecting various kinds of system data such as CPU, memory, and disk usage. They can be included in the operating system or can be part of individual applications. Windows Performance Monitor requests the current value of performance counters at specifiedtime intervals. + +System administrators often use performance counters to monitor systems for performance or behavior problems. Software developers often use performance counters to examine the resource usage of their programs. + +This package provides the `System.Diagnostics.PerformanceCounter.dll` assembly, which contains types that allow applications to interact with the Windows performance counters. ## Key Features -* -* -* +* Can be used to read existing predefined or custom counters. +* Can be used for publishing (writing) data to custom counters. +* Can collect performance counters from the local machine or from a remote machine. ## How to Use +```cs +using System; +using System.Collections.Generic; +using System.Diagnostics; + +public class App +{ + public static void Main() + { + List samples = []; + + // If the category does not exist, create the category and exit. + // Performance counters should not be created and immediately used. + // There is a latency time to enable the counters, they should be created + // prior to executing the application that uses the counters. + // Execute this sample a second time to use the category. + if (SetupCategory()) + { + return; + } + + CollectSamples(samples); + CalculateResults(samples); + } + + private static bool SetupCategory() + { + if (PerformanceCounterCategory.Exists("AverageCounter64SampleCategory")) + { + Console.WriteLine("Category exists - AverageCounter64SampleCategory"); + return false; + } + + CounterCreationDataCollection counterDataCollection = []; + + // Add the counter. + CounterCreationData averageCount64 = new() + { + CounterType = PerformanceCounterType.AverageCount64, + CounterName = "AverageCounter64Sample" + }; + counterDataCollection.Add(averageCount64); + + // Add the base counter. + CounterCreationData averageCount64Base = new() + { + CounterType = PerformanceCounterType.AverageBase, + CounterName = "AverageCounter64SampleBase" + }; + counterDataCollection.Add(averageCount64Base); + + // Create the category. + PerformanceCounterCategory.Create("AverageCounter64SampleCategory", + "Demonstrates usage of the AverageCounter64 performance counter type.", + PerformanceCounterCategoryType.SingleInstance, counterDataCollection); + + return true; + } + + private static void CollectSamples(List samples) + { + // Create the counters + + PerformanceCounter avgCounter64Sample = new PerformanceCounter("AverageCounter64SampleCategory", + "AverageCounter64Sample", + false) + { + RawValue = 0 + }; + + PerformanceCounter avgCounter64SampleBase = new PerformanceCounter("AverageCounter64SampleCategory", + "AverageCounter64SampleBase", + false) + { + RawValue = 0 + }; + + Random r = new(DateTime.Now.Millisecond); + + for (int j = 0; j < 100; j++) + { + int value = r.Next(1, 10); + Console.Write(j + " = " + value); + + avgCounter64Sample.IncrementBy(value); + + avgCounter64SampleBase.Increment(); + + if ((j % 10) == 9) + { + OutputSample(avgCounter64Sample.NextSample()); + samples.Add(avgCounter64Sample.NextSample()); + } + else + { + Console.WriteLine(); + } + + System.Threading.Thread.Sleep(50); + } + } + + private static void CalculateResults(List samples) + { + for (int i = 0; i < (samples.Count - 1); i++) + { + // Output the sample. + OutputSample(samples[i]); + OutputSample(samples[i + 1]); + + // Use .NET to calculate the counter value. + Console.WriteLine($".NET computed counter value = {CounterSampleCalculator.ComputeCounterValue(samples[i], samples[i + 1])}"); + + // Calculate the counter value manually. + Console.WriteLine($"My computed counter value = {MyComputeCounterValue(samples[i], samples[i + 1])}"); + } + } + + // Description - This counter type shows how many items are processed, on average, + // during an operation. Counters of this type display a ratio of the items + // processed (such as bytes sent) to the number of operations completed. The + // ratio is calculated by comparing the number of items processed during the + // last interval to the number of operations completed during the last interval. + // Generic type - Average + // Formula - (N1 - N0) / (D1 - D0), where the numerator (N) represents the number + // of items processed during the last sample interval and the denominator (D) + // represents the number of operations completed during the last two sample + // intervals. + // Average (Nx - N0) / (Dx - D0) + // Example PhysicalDisk\ Avg. Disk Bytes/Transfer + private static float MyComputeCounterValue(CounterSample s0, CounterSample s1) + { + float numerator = (float)s1.RawValue - s0.RawValue; + float denomenator = (float)s1.BaseValue - s0.BaseValue; + float counterValue = numerator / denomenator; + return counterValue; + } + + private static void OutputSample(CounterSample s) + { + Console.WriteLine("\r\n+++++++++++"); + Console.WriteLine("Sample values - \r\n"); + Console.WriteLine($" BaseValue = {s.BaseValue}"); + Console.WriteLine($" CounterFrequency = {s.CounterFrequency}"); + Console.WriteLine($" CounterTimeStamp = {s.CounterTimeStamp}"); + Console.WriteLine($" CounterType = {s.CounterType}"); + Console.WriteLine($" RawValue = {s.RawValue}"); + Console.WriteLine($" SystemFrequency = {s.SystemFrequency}"); + Console.WriteLine($" TimeStamp = {s.TimeStamp}"); + Console.WriteLine($" TimeStamp100nSec = {s.TimeStamp100nSec}"); + Console.WriteLine("++++++++++++++++++++++"); + } +} +``` + +Notes: + +* This assembly is only supported on Windows operating systems. +* Only the administrator of the computer or users in the Performance Logs User Group can log counter data. Users in the Administrator group can log counter data only if the tool they use to log counter data is started from a Command Prompt window that is opened with `Run as administrator...`. Any users in interactive logon sessions can view counter data. However, users in non-interactive logon sessions must be in the Performance Monitoring Users group to view counter data. + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace: + +* [`System.Diagnostics.CounterCreationData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterCreationData) +* [`System.Diagnostics.CounterCreationDataCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterCreationDataCollection) +* [`System.Diagnostics.CounterSample`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterSample) +* [`System.Diagnostics.CounterSampleCalculator`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterSampleCalculator) +* [`System.Diagnostics.ICollectData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.ICollectData) +* [`System.Diagnostics.InstanceData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.InstanceData) +* [`System.Diagnostics.InstanceDataCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.InstanceDataCollection) +* [`System.Diagnostics.InstanceDataCollectionCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.InstanceDataCollectionCollection) +* [`System.Diagnostics.PerformanceCounter`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounter) +* [`System.Diagnostics.PerformanceCounterCategory`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterCategory) +* [`System.Diagnostics.PerformanceCounterCategoryType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterCategoryType) +* [`System.Diagnostics.PerformanceCounterInstanceLifetime`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterInstanceLifetime) +* [`System.Diagnostics.PerformanceCounterManager`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterManager) +* [`System.Diagnostics.PerformanceCounterType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterType) + +Under the [`System.Diagnostics.PerformanceData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData) namespace: + +* [`System.Diagnostics.PerformanceData.CounterData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterData) +* [`System.Diagnostics.PerformanceData.CounterSet`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSet) +* [`System.Diagnostics.PerformanceData.CounterSetInstance`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSetInstance) +* [`System.Diagnostics.PerformanceData.CounterSetInstanceCounterDataSet`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSetInstanceCounterDataSet) +* [`System.Diagnostics.PerformanceData.CounterSetInstanceType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSetInstanceType) +* [`System.Diagnostics.PerformanceData.CounterType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterType) ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Microsoft Learn - System.Diagnostics.PerformanceCounter API reference](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.performancecounter?view=dotnet-plat-ext-7.0) +* [Windows App Development - Performance Counters](https://learn.microsoft.com/en-us/windows/win32/perfctrs/performance-counters-portal) +* [Windows Performance and Reliability - Windows Performance Monitor](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc749249(v=ws.11)) +* [Windows Server - perfmon](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/perfmon) +* [GitHub - Source code](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Diagnostics.PerformanceCounter) ## Related Packages +* [System.Diagnostics.EventLog](https://www.nuget.org/packages/System.Diagnostics.EventLog) + ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Diagnostics.PerformanceCounter** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 5cc655db0c358e0352425984e47c7bfb1e186fe8 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Tue, 5 Sep 2023 10:12:30 -0700 Subject: [PATCH 204/345] Add package readme for System.Speech --- src/libraries/System.Speech/src/PACKAGE.md | 85 ++++++++++++++++++---- 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index 2709a6e84e284f..76c80a6075f025 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -1,44 +1,101 @@ ## About +Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other non-Windows platforms. - +This package is provided primarily for compatibility with code being ported from .NETFramework and is not accepting new features. ## Key Features -* -* -* +* Recognize speech as text in a given language and grammar. +* Synthesize text as speech. +* Support for [Speech Recognition Grammar v1.0](https://www.w3.org/TR/speech-grammar/) documents ## How to Use +### Synthesis example +```C# +using System.Speech.Synthesis; + +// Initialize a new instance of the SpeechSynthesizer. +SpeechSynthesizer synth = new SpeechSynthesizer(); + +// Configure the audio output. +synth.SetOutputToDefaultAudioDevice(); + +// Speak a string, synchronously +synth.Speak("Hello World!"); + +// Speak a string asynchronously +var prompt = synth.SpeakAsync("Goodnight Moon!"); + +while(!prompt.IsCompleted) +{ + Console.WriteLine("speaking..."); + Thread.Sleep(500); +} +``` + +### Recognition example +```C# +// Create a new SpeechRecognitionEngine instance. +using SpeechRecognizer recognizer = new SpeechRecognizer(); +using ManualResetEvent exit = new ManualResetEvent(false); + +// Create a simple grammar that recognizes "red", "green", "blue", or "exit". +Choices choices = new Choices(); +choices.Add(new string[] { "red", "green", "blue", "exit" }); + +// Create a GrammarBuilder object and append the Choices object. +GrammarBuilder gb = new GrammarBuilder(); +gb.Append(choices); + +// Create the Grammar instance and load it into the speech recognition engine. +Grammar g = new Grammar(gb); +recognizer.LoadGrammar(g); + +// Register a handler for the SpeechRecognized event. +recognizer.SpeechRecognized += (s, e) => +{ + Console.WriteLine($"Recognized: {e.Result.Text}, Confidence: {e.Result.Confidence}"); + if (e.Result.Text == "exit") + { + exit.Set(); + } +}; + +// Emulate +Console.WriteLine("Emulating \"red\"."); +recognizer.EmulateRecognize("red"); + +Console.WriteLine("Speak red, green, blue, or exit please..."); + +exit.WaitOne(); +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `System.Speech.Recognition.SpeechRecognizer` +* `System.Speech.Synthesis.SpeechSynthesizer` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - +* [Conceptual documentation](https://learn.microsoft.com/en-us/previous-versions/office/developer/speech-technologies/hh361625(v%3doffice.14)) +* [Speech.Recognition API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.speech.recognition) +* [Speech.Synthesis API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.speech.synthesis) ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Speech** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From a8b30f8fc19cad1a5ef50f7f85378df258ad5ab2 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 11:20:28 -0700 Subject: [PATCH 205/345] Fill Microsoft.Extensions.Logging.Abstraction doc --- .../src/PACKAGE.md | 136 ++++++++++++++++-- 1 file changed, 128 insertions(+), 8 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md index 534ef37b23d3b0..400958a0a194a4 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/PACKAGE.md @@ -2,40 +2,160 @@ +`Microsoft.Extensions.Logging.Abstractions` provides abstractions of logging. Interfaces defined in this package are implemented by classes in [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging/) and other logging packages. +This package includes a logging source generator that produces highly efficient and optimized code for logging message methods. ## Key Features -* -* -* +* Define main logging abstraction interfaces like ILogger, ILoggerFactory, ILoggerProvider, etc. ## How to Use +#### Custom logger provider implementation example + +```C# +using Microsoft.Extensions.Logging; + +public sealed class ColorConsoleLogger : ILogger +{ + private readonly string _name; + private readonly Func _getCurrentConfig; + + public ColorConsoleLogger( + string name, + Func getCurrentConfig) => + (_name, _getCurrentConfig) = (name, getCurrentConfig); + + public IDisposable? BeginScope(TState state) where TState : notnull => default!; + + public bool IsEnabled(LogLevel logLevel) => + _getCurrentConfig().LogLevelToColorMap.ContainsKey(logLevel); + + public void Log( + LogLevel logLevel, + EventId eventId, + TState state, + Exception? exception, + Func formatter) + { + if (!IsEnabled(logLevel)) + { + return; + } + + ColorConsoleLoggerConfiguration config = _getCurrentConfig(); + if (config.EventId == 0 || config.EventId == eventId.Id) + { + ConsoleColor originalColor = Console.ForegroundColor; + + Console.ForegroundColor = config.LogLevelToColorMap[logLevel]; + Console.WriteLine($"[{eventId.Id,2}: {logLevel,-12}]"); + + Console.ForegroundColor = originalColor; + Console.Write($" {_name} - "); + + Console.ForegroundColor = config.LogLevelToColorMap[logLevel]; + Console.Write($"{formatter(state, exception)}"); + + Console.ForegroundColor = originalColor; + Console.WriteLine(); + } + } +} + +``` + +#### Create logs + +```csharp + +// Worker class that uses logger implementation of teh interface ILogger + +public sealed class Worker : BackgroundService +{ + private readonly ILogger _logger; + + public Worker(ILogger logger) => + _logger = logger; + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + _logger.LogInformation("Worker running at: {time}", DateTimeOffset.UtcNow); + await Task.Delay(1_000, stoppingToken); + } + } +} + +``` + +#### Use source generator + +```csharp +public static partial class Log +{ + [LoggerMessage( + EventId = 0, + Level = LogLevel.Critical, + Message = "Could not open socket to `{hostName}`")] + public static partial void CouldNotOpenSocket(this ILogger logger, string hostName); +} + +public partial class InstanceLoggingExample +{ + private readonly ILogger _logger; + + public InstanceLoggingExample(ILogger logger) + { + _logger = logger; + } + + [LoggerMessage( + EventId = 0, + Level = LogLevel.Critical, + Message = "Could not open socket to `{hostName}`")] + public partial void CouldNotOpenSocket(string hostName); +} + +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `Microsoft.Extensions.Logging.ILogger` +* `Microsoft.Extensions.Logging.ILoggerProvider` +* `Microsoft.Extensions.Logging.ILoggerFactory` +* `Microsoft.Extensions.Logging.ILogger` +* `Microsoft.Extensions.Logging.LogLevel` +* `Microsoft.Extensions.Logging.Logger` +* `Microsoft.Extensions.Logging.LoggerMessage` +* `Microsoft.Extensions.Logging.Abstractions.NullLogger` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/logging) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging) ## Related Packages +[Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) +[Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Console) +[Microsoft.Extensions.Logging.Debug](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Debug) +[Microsoft.Extensions.Logging.EventSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventSource) +[Microsoft.Extensions.Logging.EventLog](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventLog) +[Microsoft.Extensions.Logging.TraceSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.TraceSource) ## Feedback & Contributing From de6fd761b82f9112ee177f8656f527a255cf4f1c Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 12:09:35 -0700 Subject: [PATCH 206/345] Fill Microsoft.Extensions.Logging doc --- .../src/PACKAGE.md | 121 ++++++++++++++++-- 1 file changed, 111 insertions(+), 10 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md index 302b93b4956421..607283d3eb7486 100644 --- a/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md @@ -1,20 +1,112 @@ ## About - - +`Microsoft.Extensions.Logging` is combined with a core logging abstraction under `Microsoft.Extensions.Logging.Abstractions`. This abstraction is available in our basic built-in implementations like console, event log, and debug (Debug.WriteLine) logging. ## Key Features -* -* -* +* Provide concrete implementations of ILoggerFactory +* Provide extension methods for service collections, logger builder, and activity tracking +* Provide logging filtering extension methods for logger builder ## How to Use +Prior to .NET 6, we only had two forms possible for doing logging, using `Microsoft.Extensions.Logging`: + +```cs +public class LoggingSample1 +{ + private ILogger _logger; + + public LoggingSample1(ILogger logger) + { + _logger = logger; + } + + public void LogMethod(string name) + { + _logger.LogInformation("Hello {name}", name); + } +} +``` + +Here are some problems with the LoggingSample1 sample using `LogInformation`, `LogWarning`, etc.: + +1. We can provide event ID through these APIs, but they are not required today. Which leads to bad usages in real systems that want to react or detect specific event issues being logged. +2. Parameters passed are processed before LogLevel checks; this leads to unnecessary code paths getting triggered even when logging is disabled for a log level. +3. It requires parsing of message string on every use to find templates to substitute. + +Because of these problems, the more efficient runtime approach recommended as best practices is to use LoggerMessage.Define APIs instead, illustrated below with LoggingSample2: + +```cs +public class LoggingSample2 +{ + private ILogger _logger; + + public LoggingSample2(ILogger logger) + { + _logger = logger; + } + + public void LogMethod(string name) + { + Log.LogName(_logger, name); + } + + private static class Log + { + private static readonly Action _logName = LoggerMessage.Define(LogLevel.Information, 0, @"Hello {name}"); + + public static void LogName(ILogger logger, string name) + { + _logName(logger, name, null!); + } + } +} +``` + +To reach a balance between performance and usability we added the compile-time logging source generator feature in .NET 6, to learn more about it and learn how to use a source generator to create log messages check out [this documentation](https://learn.microsoft.com/dotnet/core/extensions/logger-message-generator). + +```csharp + +public partial class InstanceLoggingExample +{ + private readonly ILogger _logger; + + public InstanceLoggingExample(ILogger logger) + { + _logger = logger; + } + + [LoggerMessage( + EventId = 0, + Level = LogLevel.Critical, + Message = "Could not open socket to `{hostName}`")] + public partial void CouldNotOpenSocket(string hostName); +} +``` + +#### Baggage and Tags for `ActivityTrackingOptions` + +.NET 5.0 exposed a new feature that allows configuring the logger builder with the `ActivityTrackingOption` to add the tracing context Span Id, Trace Id, Parent Id, Trace state, and Trace flags to the logging scope. The tracing context usually carried in `Activity.Current`. + +.NET 6.0 Preview 1 extended this feature to include more tracing context properties which are the Baggage and the Tags: + +```cs + var loggerFactory = LoggerFactory.Create(logging => + { + logging.Configure(options => + { + options.ActivityTrackingOptions = ActivityTrackingOptions.Tags | ActivityTrackingOptions.Baggage; + }).AddSimpleConsole(options => + { + options.IncludeScopes = true; + }); + }); +``` ## Main Types @@ -22,20 +114,29 @@ The main types provided by this library are: -* `` -* `` -* `` +* LoggingServiceCollectionExtensions +* LoggerFactory +* LoggerFactoryOptions +* LoggingBuilderExtensions +* ActivityTrackingOptions +* FilterLoggingBuilderExtensions ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/logging) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging) ## Related Packages +[Microsoft.Extensions.Logging.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions) +[Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Console) +[Microsoft.Extensions.Logging.Debug](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Debug) +[Microsoft.Extensions.Logging.EventSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventSource) +[Microsoft.Extensions.Logging.EventLog](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventLog) +[Microsoft.Extensions.Logging.TraceSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.TraceSource) ## Feedback & Contributing From 0c4d908af8af33ef1feddc4bbf164e96e681e3ea Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 12:36:37 -0700 Subject: [PATCH 207/345] Fill Microsoft.Extensions.Logging.Console doc --- .../src/PACKAGE.md | 83 ++++++++++++++++--- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md index 582bba45f12169..b35f529af9c06c 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md @@ -1,20 +1,71 @@ ## About - - +`Microsoft.Extensions.Logging.Console` provides a Console logger provider implementation for Microsoft.Extensions.Logging. It provides extension methods for the [ILoggingBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggingbuilder) and [ILoggerProviderConfiguration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.configuration.iloggerproviderconfiguration-1) classes. ## Key Features -* -* -* +* Allow logging to the console using the [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging/) package. +* Provide extension methods for the [ILoggingBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggingbuilder) and [ILoggerProviderConfiguration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.configuration.iloggerproviderconfiguration-1) classes. + ## How to Use +```csharp +using System; +using Microsoft.Extensions.Logging; + +namespace ConsoleLoggerSample +{ + class Program + { + static void Main(string[] args) + { + // Create a logger factory with a console provider + using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); + + // Create a logger with the category name of the current class + ILogger logger = loggerFactory.CreateLogger(); + + // Log some messages with different log levels and message templates + logger.LogTrace("This is a trace message."); + logger.LogDebug("This is a debug message."); + logger.LogInformation("Hello {Name}!", "World"); + logger.LogWarning("This is a warning message."); + logger.LogError("This is an error message."); + logger.LogCritical("This is a critical message."); + + // Use structured logging to capture complex data + var person = new Person { Name = "Alice", Age = 25 }; + logger.LogInformation("Created a new person: {@Person}", person); + + // Use exception logging to capture the details of an exception + try + { + throw new Exception("Something went wrong."); + } + catch (Exception ex) + { + logger.LogError(ex, "An exception occurred."); + } + + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + } + + // A simple class to demonstrate structured logging + class Person + { + public string Name { get; set; } + public int Age { get; set; } + } +} + +``` ## Main Types @@ -22,20 +73,32 @@ The main types provided by this library are: -* `` -* `` -* `` +* `ConsoleLoggerProvider` +* `ConsoleLoggerSettings` +* `ConsoleLoggerOptions` +* `ConsoleLoggerExtensions` +* `ConsoleFormatter` +* `ConsoleFormatterOptions` +* `JsonConsoleFormatterOptions` +* `SimpleConsoleFormatterOptions` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/logging) +* [Console log formatter](https://learn.microsoft.com/dotnet/core/extensions/console-log-formatter) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging) ## Related Packages +[Microsoft.Extensions.Logging.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions) +[Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) +[Microsoft.Extensions.Logging.Debug](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Debug) +[Microsoft.Extensions.Logging.EventSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventSource) +[Microsoft.Extensions.Logging.EventLog](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventLog) +[Microsoft.Extensions.Logging.TraceSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.TraceSource) ## Feedback & Contributing From 9e084bea10bfc762cf80dcdc9da5b87e0fced09f Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 12:57:26 -0700 Subject: [PATCH 208/345] Fill Microsoft.Extensions.Logging.Debug doc --- .../src/PACKAGE.md | 75 ++++++++++++++++--- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md index b933164215cb84..8a5c652290643e 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md @@ -1,20 +1,72 @@ ## About - +`Microsoft.Extensions.Logging.Debug` provides a Debug output logger provider implementation for Microsoft.Extensions.Logging. This logger logs messages to a debugger monitor by writing messages with `System.Diagnostics.Debug.WriteLine()`. ## Key Features -* -* -* +* Allow logging to the debugger output. +* Provide extensions method for the [ILoggingBuilder](https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggingbuilder) class to easily enable this Debug logger. ## How to Use +```csharp +using System; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Debug; + +namespace DebugLoggerSample +{ + class Program + { + static void Main(string[] args) + { + // Create a logger factory with a debug provider + using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddDebug()); + + // Create a logger with the category name of the current class + ILogger logger = loggerFactory.CreateLogger(); + + // Log some messages with different log levels and message templates + logger.LogTrace("This is a trace message."); + logger.LogDebug("This is a debug message."); + logger.LogInformation("Hello {Name}!", "World"); + logger.LogWarning("This is a warning message."); + logger.LogError("This is an error message."); + logger.LogCritical("This is a critical message."); + + // Use structured logging to capture complex data + var person = new Person { Name = "Alice", Age = 25 }; + logger.LogInformation("Created a new person: {@Person}", person); + + // Use exception logging to capture the details of an exception + try + { + throw new Exception("Something went wrong."); + } + catch (Exception ex) + { + logger.LogError(ex, "An exception occurred."); + } + + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + } + + // A simple class to demonstrate structured logging + class Person + { + public string Name { get; set; } + public int Age { get; set; } + } +} + +``` ## Main Types @@ -22,18 +74,23 @@ The main types provided by this library are: -* `` -* `` -* `` +* `DebugLoggerProvider` +* `DebugLoggerFactoryExtensions` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/logging) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging) ## Related Packages +[Microsoft.Extensions.Logging.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions) +[Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) +[Microsoft.Extensions.Logging.Console](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Console) +[Microsoft.Extensions.Logging.EventSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventSource) +[Microsoft.Extensions.Logging.EventLog](https://www.nuget.org/packages/Microsoft.Extensions.Logging.EventLog) +[Microsoft.Extensions.Logging.TraceSource](https://www.nuget.org/packages/Microsoft.Extensions.Logging.TraceSource) From 030a4db778ab02074b1ba43beb1dbed1a1a8261b Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 5 Sep 2023 17:34:15 -0400 Subject: [PATCH 209/345] Add Microsoft.Bcl.Async package.md details --- .../src/PACKAGE.md | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md index 7a9788f170fb42..a4a5af4a370f6f 100644 --- a/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md @@ -1,41 +1,61 @@ ## About - - - +As of C# 8, the C# language has support for producing and consuming asynchronous iterators. The library types in support of those features are available in .NET Core 3.0 and newer as well as in .NET Standard 2.1. This library provides the necessary definitions of those types to support these language features on .NET Framework and on .NET Standard 2.0. This library is not necessary nor recommended when targeting versions of .NET that include the relevant support. ## Key Features -* -* -* +* Enables the use of C# async iterators on older .NET platforms ## How to Use +```C# +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +internal static class Program +{ + private static async Task Main() + { + Console.WriteLine("Starting..."); + await foreach (var value in GetValuesAsync()) + { + Console.WriteLine(value); + } + Console.WriteLine("Finished!"); + + static async IAsyncEnumerable GetValuesAsync() + { + for (int i = 0; i < 10; i++) + { + await Task.Delay(TimeSpan.FromSeconds(1)); + yield return i; + } + } + } +} +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `IAsyncEnumerable` +* `IAsyncEnumerator` +* `IAsyncDisposable` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - +* [C# Feature Specification](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/async-streams) +* [Walkthrough article](https://learn.microsoft.com/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8) ## Feedback & Contributing From 00c840673390caf4ca72c526a0e09776d30d4091 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 5 Sep 2023 17:43:54 -0400 Subject: [PATCH 210/345] Add System.Threading.Channels package.md details --- .../System.Threading.Channels/src/PACKAGE.md | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Threading.Channels/src/PACKAGE.md b/src/libraries/System.Threading.Channels/src/PACKAGE.md index 2709a6e84e284f..cd9c6b829e10bb 100644 --- a/src/libraries/System.Threading.Channels/src/PACKAGE.md +++ b/src/libraries/System.Threading.Channels/src/PACKAGE.md @@ -2,43 +2,72 @@ - +The `System.Threading.Channels` library provides types for passing data asynchronously between producers and consumers. ## Key Features -* -* -* +* Abstractions representing channels for one or more producers to publish data to one or more consumers +* APIs focused on asynchronous production and consumption of data +* Factory methods for producing multiple kinds of channels ## How to Use +```C# +using System; +using System.Threading.Channels; +using System.Threading.Tasks; + +Channel channel = Channel.CreateUnbounded(); + +Task producer = Task.Run(async () => +{ + int i = 0; + while (true) + { + channel.Writer.TryWrite(i++); + await Task.Delay(TimeSpan.FromSeconds(1)); + } +}); + +Task consumer = Task.Run(async () => +{ + await foreach (int value in channel.Reader.ReadAllAsync()) + { + Console.WriteLine(value); + } +}); + +await Task.WhenAll(producer, consumer); +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `System.Threading.Channel` +* `System.Threading.Channel` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Overview](https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.threading.channels) ## Related Packages +https://www.nuget.org/packages/System.Threading.Tasks.Dataflow/ + ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Threading.Channels** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 9c0253dbe4b8e86f47b780ca0a047431c0423040 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 15:00:48 -0700 Subject: [PATCH 211/345] Fill Microsoft.Extensions.Primitives doc --- .../src/PACKAGE.md | 109 ++++++++++++++---- 1 file changed, 87 insertions(+), 22 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md index db0a84ec52694c..432abfa969f057 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Primitives/src/PACKAGE.md @@ -1,44 +1,109 @@ ## About - - - +`Microsoft.Extensions.Primitives` contains isolated types that are used in many places within console or ASP.NET Core applications using framework extensions. ## Key Features - - -* -* -* +* IChangeToken: An interface that represents a token that can notify when a change occurs. This can be used to trigger actions or invalidate caches when something changes. For example, the configuration and file providers libraries use this interface to reload settings or files when they are modified. +* StringValues: A struct that represents a single string or an array of strings. This can be used to efficiently store and manipulate multiple values that are logically a single value. For example, the HTTP headers and query strings libraries use this struct to handle multiple values for the same key. +* StringSegment: A struct that represents a substring of another string. This can be used to avoid allocating new strings when performing operations on parts of a string. For example, the configuration and logging libraries use this struct to parse and format strings. ## How to Use - - +#### IChangeToken with configuration example + +```C# +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Primitives; +using System; + +class Program +{ + static void Main(string[] args) + { + // Create a configuration builder + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(Environment.CurrentDirectory) + // appsettings.json expected to have the following contents: + // { + // "SomeKey": "SomeValue" + // } + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + + // Build the configuration + IConfiguration configuration = configurationBuilder.Build(); + + // Create a change token for the configuration + IChangeToken changeToken = configuration.GetReloadToken(); + + // Attach a change callback + IDisposable changeTokenRegistration = changeToken.RegisterChangeCallback(state => + { + Console.WriteLine("Configuration changed!"); + IConfigurationRoot root = (IConfigurationRoot)state; + var someValue = root["SomeKey"]; // Access the updated configuration value + Console.WriteLine($"New value of SomeKey: {someValue}"); + }, configuration); + + // go and update the value of the key SomeKey in appsettings.json. + // The change callback will be invoked when the file is saved. + Console.WriteLine("Listening for configuration changes. Press any key to exit."); + Console.ReadKey(); + + // Clean up the change token registration when no longer needed + changeTokenRegistration.Dispose(); + } +} +``` +#### StringValues example + +```C# +using System; +using Microsoft.Extensions.Primitives; + +namespace StringValuesSample +{ + class Program + { + static void Main(string[] args) + { + // Create a StringValues object from a single string or an array of strings + StringValues single = "Hello"; + StringValues multiple = new string[] { "Hello", "World" }; + + // Use the implicit conversion to string or the ToString method to get the values + Console.WriteLine($"Single: {single}"); // Single: Hello + Console.WriteLine($"Multiple: {multiple}"); // Multiple: Hello,World + + // Use the indexer, the Count property, and the IsNullOrEmpty method to access the values + Console.WriteLine($"Multiple[1]: {multiple[1]}"); // Multiple[1]: World + Console.WriteLine($"Single.Count: {single.Count}"); // Single.Count: 1 + Console.WriteLine($"Multiple.IsNullOrEmpty: {StringValues.IsNullOrEmpty(multiple)}"); // Multiple.IsNullOrEmpty: False + + // Use the Equals method or the == operator to compare two StringValues objects + Console.WriteLine($"single == \"Hello\": {single == "Hello"}"); // single == "Hello": True + Console.WriteLine($"multiple == \"Hello\": {multiple == "Hello"}"); // multiple == "Hello": False + } + } +} +``` ## Main Types - - The main types provided by this library are: -* `` -* `` -* `` +* `IChangeToken` +* `StringValues` +* `StringSegment` ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/primitives) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.primitives) ## Related Packages - +* [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) ## Feedback & Contributing - - Microsoft.Extensions.Primitives is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 685a2138a27a543aedd9d04e15018a95f1113252 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 15:51:53 -0700 Subject: [PATCH 212/345] Remove trailing spaces from Speech doc file --- src/libraries/System.Speech/src/PACKAGE.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index 76c80a6075f025..0b39583a424016 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -1,7 +1,7 @@ ## About -Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other non-Windows platforms. +Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other non-Windows platforms. This package is provided primarily for compatibility with code being ported from .NETFramework and is not accepting new features. @@ -18,14 +18,14 @@ This package is provided primarily for compatibility with code being ported from ### Synthesis example -```C# +```C# using System.Speech.Synthesis; -// Initialize a new instance of the SpeechSynthesizer. -SpeechSynthesizer synth = new SpeechSynthesizer(); +// Initialize a new instance of the SpeechSynthesizer. +SpeechSynthesizer synth = new SpeechSynthesizer(); -// Configure the audio output. -synth.SetOutputToDefaultAudioDevice(); +// Configure the audio output. +synth.SetOutputToDefaultAudioDevice(); // Speak a string, synchronously synth.Speak("Hello World!"); @@ -64,11 +64,11 @@ recognizer.SpeechRecognized += (s, e) => Console.WriteLine($"Recognized: {e.Result.Text}, Confidence: {e.Result.Confidence}"); if (e.Result.Text == "exit") { - exit.Set(); + exit.Set(); } }; -// Emulate +// Emulate Console.WriteLine("Emulating \"red\"."); recognizer.EmulateRecognize("red"); From 57f6eedd05ce784d66a9bd7a2dc3312a6a2eaa89 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 16:52:01 -0700 Subject: [PATCH 213/345] Fill Microsoft.Extensions.Options doc --- .../src/PACKAGE.md | 166 +++++++++++++++--- 1 file changed, 146 insertions(+), 20 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md index 220873bc79027f..ee0cc2ab6f99ee 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Options/src/PACKAGE.md @@ -1,44 +1,170 @@ ## About +`Microsoft.Extensions.Options` provides a strongly typed way of specifying and accessing settings using dependency injection and acts as a bridge between configuration, DI, and higher level libraries. This library is the glue for how an app developer uses DI to configure the behavior of a library like HttpClient Factory. This also enables user to get a strongly-typed view of their configuration. - +Within this package, you'll find an options validation source generator that generates exceptionally efficient and optimized code for validating options. +## Key Features +* Offer the IValidateOptions interface for the validation of options, along with several generic ValidateOptions classes that implement this interface. +* OptionsBuilder to configure options. +* Provide extension methods for service collections and options builder to register options and validate options. +* Supply a set of generic ConfigureNamedOptions classes that implement the IConfigureNamedOptions interface for configuring named options. +* Provide a source generator that generates validation code for options. +* Options caching, managing and monitoring. -## Key Features +## How to Use - +#### Options validation example -* -* -* +```C# +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; -## How to Use +var builder = WebApplication.CreateBuilder(args); - +builder.Services.AddControllersWithViews(); -## Main Types +// Load the configuration and validate it +builder.Services.AddOptions() + .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig)) + .ValidateDataAnnotations(); +var app = builder.Build(); - + +// Declare the option class to validate +public class MyConfigOptions +{ + public const string MyConfig = "MyConfig"; + + [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")] + public string Key1 { get; set; } + [Range(0, 1000, + ErrorMessage = "Value for {0} must be between {1} and {2}.")] + public int Key2 { get; set; } + public int Key3 { get; set; } +} +``` + +#### Using IValidateOptions to validate options + +```C# +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllersWithViews(); + +// Configuration to validate +builder.Services.Configure(builder.Configuration.GetSection( + MyConfigOptions.MyConfig)); + +// OPtions validation through the DI container +builder.Services.AddSingleton, MyConfigValidation>(); + +var app = builder.Build(); + +public class MyConfigValidation : IValidateOptions +{ + public MyConfigOptions _config { get; private set; } + + public MyConfigValidation(IConfiguration config) + { + _config = config.GetSection(MyConfigOptions.MyConfig) + .Get(); + } + + public ValidateOptionsResult Validate(string name, MyConfigOptions options) + { + string? vor = null; + var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$"); + var match = rx.Match(options.Key1!); + + if (string.IsNullOrEmpty(match.Value)) + { + vor = $"{options.Key1} doesn't match RegEx \n"; + } + + if ( options.Key2 < 0 || options.Key2 > 1000) + { + vor = $"{options.Key2} doesn't match Range 0 - 1000 \n"; + } + + if (_config.Key2 != default) + { + if(_config.Key3 <= _config.Key2) + { + vor += "Key3 must be > than Key2."; + } + } + + if (vor != null) + { + return ValidateOptionsResult.Fail(vor); + } + + return ValidateOptionsResult.Success; + } +} + +``` + +#### Options Validation Source Generator Example + +```C# +using System; +using System.ComponentModel.DataAnnotations; +using Microsoft.Extensions.Options; + +public class MyConfigOptions +{ + [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")] + public string Key1 { get; set; } + + [Range(0, 1000, + ErrorMessage = "Value for {0} must be between {1} and {2}.")] + public int Key2 { get; set; } + public int Key3 { get; set; } +} + +[OptionsValidator] +public partial class MyConfigValidation : IValidateOptions +{ + // Source generator will automatically provide the implementation of IValidateOptions + // Then you can add the validation to the DI Container using the following code: + // + // builder.Services.AddSingleton, MyConfigValidation>(); + // builder.Services.AddOptions() + // .Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig)) + // .ValidateDataAnnotations(); +} + +``` + +## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `IOptions`, `IOptionsFactory`, and `IOptionsMonitor` +* `IValidateOptions` and `ValidateOptions` +* `OptionsBuilder`, `OptionsFactory`, `OptionsMonitor`, and `OptionsManager` +* `OptionsServiceCollectionExtensions` +* `OptionsValidatorAttribute` ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/aspnet/core/fundamentals/configuration/options) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.options) ## Related Packages - +[Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging) +[Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) ## Feedback & Contributing - - Microsoft.Extensions.Options is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From e6202a785d6ef5db2cf0723e357a3c16dc44db8f Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 5 Sep 2023 17:33:29 -0700 Subject: [PATCH 214/345] Fill System.Text.Encoding.CodePages doc --- .../src/PACKAGE.md | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md b/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md index 2709a6e84e284f..87e4c8054b2fd6 100644 --- a/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md +++ b/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md @@ -1,44 +1,39 @@ ## About - +`System.Text.Encoding.CodePages` enable creating single and double bytes encodings for code pages that otherwise are available only in the desktop .NET Framework. +## Key Features +* Support single and double byte encodings for code pages that are not available in .NET Core. -## Key Features +## How to Use - +```csharp +using System.Text; -* -* -* +// Register the CodePages encoding provider at application startup to enable using single and double byte encodings. +Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); -## How to Use +// Now can create single and double byte encodings for code pages that are not available in .NET Core. +Encoding windows1252Encoding = Encoding.GetEncoding(1252); // Western European (Windows) +byte[] encodedBytes = windows1252Encoding.GetBytes("String to encode"); - +``` ## Main Types - - The main types provided by this library are: -* `` -* `` -* `` +* `CodePagesEncodingProvider` ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.text.codepagesencodingprovider) ## Related Packages - +* [System.Text.Encodings.Web](https://www.nuget.org/packages/System.Text.Encodings.Web) ## Feedback & Contributing - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +System.Text.Encoding.CodePages is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 795122ab786eb3075a8d114e694890581e18c452 Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Wed, 6 Sep 2023 09:27:14 +0200 Subject: [PATCH 215/345] Add System.IO.Ports --- src/libraries/System.IO.Ports/src/PACKAGE.md | 38 +++++++++++++------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.IO.Ports/src/PACKAGE.md b/src/libraries/System.IO.Ports/src/PACKAGE.md index 2709a6e84e284f..b450bd4318cb3e 100644 --- a/src/libraries/System.IO.Ports/src/PACKAGE.md +++ b/src/libraries/System.IO.Ports/src/PACKAGE.md @@ -1,44 +1,58 @@ ## About - - +[System.IO.Ports](https://www.nuget.org/packages/System.IO.Ports) package provides synchronous serial port file resource. Additionally, the functionality of this class can be wrapped in an internal `Stream` object, accessible through the `BaseStream` property, and passed to classes that wrap or use streams. ## Key Features -* -* -* +* synchronous and event-driven I/O +* access to pin and break states +* access to serial driver properties +* access to `Stream` object through the `BaseStream` property ## How to Use +```C# +using System.IO.Ports; + +// Provides list of available serial ports +string[] portNames = SerialPort.GetPortNames(); + +// First available port +string myPortName = portNames[0]; +int baudRate = 9600; + +SerialPort sp = new SerialPort(myPortName, baudRate); +sp.Open(); +sp.WriteLine("Hello World!"); +``` + ## Main Types -The main types provided by this library are: +The main type provided by this library is: -* `` -* `` -* `` +* `SerialPort` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [SerialPort class documentation](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport?view=dotnet-plat-ext-7.0) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/System.IO.Ports) ## Related Packages +- [System.IO.Ports](https://www.nuget.org/packages/System.IO.Ports) ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.IO.Ports** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 225186ae0beee426f181839473a75545bdd3c0d4 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 6 Sep 2023 16:40:23 +0100 Subject: [PATCH 216/345] Add System.Net.Http.Json README --- .../System.Net.Http.Json/src/PACKAGE.md | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/libraries/System.Net.Http.Json/src/PACKAGE.md b/src/libraries/System.Net.Http.Json/src/PACKAGE.md index 2709a6e84e284f..5c084900142c12 100644 --- a/src/libraries/System.Net.Http.Json/src/PACKAGE.md +++ b/src/libraries/System.Net.Http.Json/src/PACKAGE.md @@ -1,44 +1,50 @@ ## About - +Provides extension methods for `System.Net.Http.HttpClient` and `System.Net.Http.HttpContent` that facilitate serialization and deserialization of HTTP requests using System.Text.Json. +## Key Features +* Extension methods for deserializing HTTP response JSON bodies. +* Extension methods for serializing HTTP request JSON bodies. +* Extension methods for deserializing JSON from `HttpContent` instances. -## Key Features +## How to Use - +```C# +using System.Net.Http.Json; -* -* -* +using var client = new HttpClient(); -## How to Use +// Get the list of all books +Book[] books = await client.GetFromJsonAsync("https://api.contoso.com/books"); - +// Send a POST request to add a new book +var book = new Book(id: 42, "Title", "Author", publishedYear: 2023); +HttpResponseMessage response = await client.PostAsJsonAsync($"https://api.contoso.com/books/{book.id}", book); -## Main Types +if (response.IsSuccessStatusCode) + Console.WriteLine("Book added successfully."); +else + Console.WriteLine($"HTTP request failed with status code: {response.StatusCode}"); - +public record Book(int id, string title, string author, int publishedYear); +``` + +## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `HttpClientJsonExtensions` +* `HttpContentJsonExtensions` ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.net.http.json) ## Related Packages - +* [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) ## Feedback & Contributing - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Net.Http.Json** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 0597c3730f643d338efebfd6bd05135f06f411c7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 6 Sep 2023 18:18:55 +0200 Subject: [PATCH 217/345] Readme for WinHttpHandler --- .../src/PACKAGE.md | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md index 2709a6e84e284f..ab0ba9b13aab92 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md @@ -1,44 +1,48 @@ ## About - +This package provides an [`HttpMessageHandler`](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpmessagehandler) implementation backed by [Windows HTTP Services (WinHTTP)](https://learn.microsoft.com/en-us/windows/win32/winhttp/winhttp-start-page). +While the use of the default `HttpClientHandler` is highly recommended for applications targeting modern .NET, `WinHttpHandler` might help migration scenarios by providing an alternative HTTP backend for Windows that works consistently accross .NET Framework and modern .NET. +## Key Features +* Enables sending *asynchronous* HTTP requests with `HttpClient` on Windows. +* Handles authentication and credentials. +* Exposes a subset of WinHTTP options as C# properties on `WinHttpHandler`. +* Use custom proxy. +* Handle cookies. -## Key Features +## How to Use - +```C# +using System.Net; -* -* -* +using WinHttpHandler handler = new() +{ + ServerCredentials = new NetworkCredential("usr", "pwd") +}; -## How to Use +using HttpClient client = new(handler); +using HttpRequestMessage request = new(HttpMethod.Get, "https://httpbin.org/basic-auth/usr/pwd"); +using HttpResponseMessage response = await client.SendAsync(request); - +Console.WriteLine($"Status: {response.StatusCode}"); +if (response.IsSuccessStatusCode) +{ + string content = await response.Content.ReadAsStringAsync(); + Console.WriteLine(content); +} +``` ## Main Types - - The main types provided by this library are: -* `` -* `` -* `` +* `System.Net.Http.WinHttpHandler` ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.winhttphandler) ## Feedback & Contributing - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Net.Http.WinHttpHandler** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From f17e38184583b07994146f9ab6395795ab4d4ea3 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Wed, 6 Sep 2023 11:39:41 -0700 Subject: [PATCH 218/345] Fill Microsoft.Extensions.Options.ConfigurationExtensions doc --- .../src/PACKAGE.md | 143 +++++++++++++++--- 1 file changed, 122 insertions(+), 21 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md index 1609a20ac51d7b..c893fd4f0e3204 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/PACKAGE.md @@ -1,44 +1,145 @@ ## About - - - +`Microsoft.Extensions.Options.ConfigurationExtensions` provides additional configuration-specific functionality related to Options. ## Key Features - - -* -* -* +* Extension methods for OptionsBuilder for configuration binding +* Extension methods for IServiceCollection for Options configuration +* ConfigurationChangeTokenSource for monitoring configuration changes ## How to Use - +#### Options Configuration binding + +```csharp +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +class Program +{ + // appsettings.json contents: + // { + // "MyOptions": { + // "Setting1": "Value1", + // "Setting2": "Value2" + // } + // } + + static void Main(string[] args) + { + IConfiguration configuration = new ConfigurationBuilder() + .SetBasePath(Environment.CurrentDirectory) + .AddJsonFile("appsettings.json") + .Build(); + + IServiceCollection services = new ServiceCollection(); + + // Bind the configuration to MyOptions + services.Configure(configuration.GetSection("MyOptions")); + + IServiceProvider serviceProvider = services.BuildServiceProvider(); + + // Retrieve MyOptions using dependency injection + var myOptions = serviceProvider.GetRequiredService>().Value; + + // Access the bound configuration values + Console.WriteLine($"Setting1: {myOptions.Setting1}"); + Console.WriteLine($"Setting2: {myOptions.Setting2}"); + } +} + +public class MyOptions +{ + public string Setting1 { get; set; } + public string Setting2 { get; set; } +} + +``` + +#### Monitoring options configuration changes + +```csharp +// Assume we have a class that represents some options +public class MyOptions +{ + public string Name { get; set; } + public int Age { get; set; } +} + +// appsettings.json contents: +// { +// "MyOptions": { +// "Name": "Alice", +// "Age": 25 +// } +// } + +// Assume we have a configuration object that contains some settings +var config = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .Build(); + +// We can use the ConfigurationChangeTokenSource to create a change token source for the options +var changeTokenSource = new ConfigurationChangeTokenSource(config.GetSection("MyOptions")); + +// We can register the change token source with the options monitor +services.AddOptions() + .Configure(options => + { + // Configure the options with the configuration values + config.GetSection("MyOptions").Bind(options); + }) + .AddChangeTokenSource(changeTokenSource); + +// Now we can inject the options monitor into any class that needs them +public class MyClass +{ + private readonly IOptionsMonitor _optionsMonitor; + + public MyClass(IOptionsMonitor optionsMonitor) + { + _optionsMonitor = optionsMonitor; + } + + public void DoSomething() + { + // Can access the current options value like this + var options = _optionsMonitor.CurrentValue; + var name = options.Name; + var age = options.Age; + // Do something with name and age + + // Can also register a callback to be notified when the options change + _optionsMonitor.OnChange(newOptions => + { + // Do something when the options change + }); + } +} + +``` ## Main Types - - The main types provided by this library are: -* `` -* `` -* `` +* `ConfigurationChangeTokenSource` +* `OptionsBuilderConfigurationExtensions` +* `OptionsConfigurationServiceCollectionExtensions` ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/aspnet/core/fundamentals/configuration/options) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.options) ## Related Packages - +* [Microsoft.Extensions.Options](https://www.nuget.org/packages/Microsoft.Extensions.Options) +* [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) +* [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection) ## Feedback & Contributing - - Microsoft.Extensions.Options.ConfigurationExtensions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From c5653f7700797178516d757851625c488b58691a Mon Sep 17 00:00:00 2001 From: Natalia Kondratyeva Date: Wed, 6 Sep 2023 22:04:45 +0200 Subject: [PATCH 219/345] Update Microsoft.Extensions.Http --- .../Microsoft.Extensions.Http/src/PACKAGE.md | 57 +++++++++++++++---- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md index 7effd1dfd486cf..bf1cc0ef79e7e2 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md @@ -2,43 +2,80 @@ - +[Microsoft.Extensions.Http](https://www.nuget.org/packages/Microsoft.Extensions.Http) package provides `AddHttpClient` extension methods for `IServiceCollection`, `IHttpClientFactory` interface and its default implementation. This provides the ability to set up named `HttpClient` configurations in a DI container and later retrieve them via an injected `IHttpClientFactory` instance. ## Key Features -* -* -* +* The package allows to fluently set up multiple `HttpClient` configurations for applications that use DI via `AddHttpClient` extension method. +* `HttpClientFactory` caches `HttpMessageHandler` instances per configuration name, which allows to reuse resources between `HttpClient` instances to avoid port exhaustion. +* `HttpClientFactory` manages lifetime of `HttpMessageHandler` instances and recycles connections to avoid losing DNS changes. ## How to Use +Note that lifetime management of `HttpClient` instances created by `HttpClientFactory` is completely different from instances created manually. The strategies are to use either short-lived clients created by `HttpClientFactory` or long-lived clients with `PooledConnectionLifetime` set up. For more information, see the [HttpClient lifetime management section](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#httpclient-lifetime-management) in the conceptual docs and [Guidelines for using HTTP clients](https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines). + +### Configuring HttpClient + +```c# +builder.Services.AddHttpClient("foo"); // adding an HttpClient named "foo" with a default configuration + +builder.Services.AddHttpClient("example", c => c.BaseAddress = new Uri("https://www.example.com")) // configuring HttpClient itself + .AddHttpMessageHandler() // adding additional delegating handlers to form a message handler chain + .ConfigurePrimaryHttpMessageHandler(b => new HttpClientHandler() { AllowAutoRedirect = false }) // configuring primary handler + .SetHandlerLifetime(TimeSpan.FromMinutes(30)); // changing the handler recycling interval +``` + +### Using the configured HttpClient + +```c# +public class MyService +{ + public MyService(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; // injecting the factory + } + + private Task GetExampleAsync(Uri uri, CancellationToken ct) + { + HttpClient exampleClient = _httpClientFactory.CreateClient("example"); // creating the client for the specified name + return exampleClient.GetStringAsync(uri, ct); // using the client + } +} +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `IHttpClientFactory` +* `IHttpMessageHandlerFactory` +* `HttpClientFactoryServiceCollectionExtensions` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory) + * Also see [HttpClient guidelines](https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines) conceptual doc +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.net.http?view=dotnet-plat-ext-7.0) + * Also see [`AddHttpClient` extension method](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.httpclientfactoryservicecollectionextensions?view=dotnet-plat-ext-7.0) API doc ## Related Packages +* [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection/) +* [Microsoft.Extensions.Http.Polly](https://www.nuget.org/packages/Microsoft.Extensions.Http.Polly) +* [Microsoft.Extensions.Http.Telemetry](https://www.nuget.org/packages/Microsoft.Extensions.Http.Telemetry) + ## Feedback & Contributing -Microsoft.Extensions.Http is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Http is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From dd2fa092fbf69aac8d72d0bd554774d220e78f06 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Wed, 6 Sep 2023 13:56:28 -0700 Subject: [PATCH 220/345] Fill Microsoft.Bcl.TimeProvider doc --- .../Microsoft.Bcl.TimeProvider/src/PACKAGE.md | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md index 90901aee2d59c7..bf767f3354d39a 100644 --- a/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md @@ -1,44 +1,58 @@ ## About - - - +Microsoft.Bcl.TimeProvider provides time abstraction support for apps targeting .NET 7 and earlier, as well as those intended for the .NET Framework. For apps targeting .NET 8 and newer versions, referencing this package is unnecessary, as the types it contains are already included in the .NET 8 and higher platform versions. ## Key Features - - -* -* -* +* Provides a common abstraction for time-related operations. ## How to Use - +```csharp +using System; + +// A class that uses TimeProvider to get the current time in Utc coordinates +public class UtcClock +{ + private readonly TimeProvider _timeProvider; + + // Constructor that takes a TimeProvider as a dependency + public Clock(TimeProvider timeProvider) + { + _timeProvider = timeProvider; + } + + // A method that returns the current time as a string + public string GetTime() + { + return _timeProvider.GetLocalNow().ToString("HH:mm:ss"); + } +} + +// A class that inherits from TimeProvider and overrides the GetLocalNow method +public class UtcTimeProvider : TimeProvider +{ + // Override the GetLocalNow method to always return UTC time + public override DateTimeOffset GetLocalNow() + { + return TimeProvider.System.GetUtcNow(); + } +} + +``` ## Main Types - - The main types provided by this library are: -* `` -* `` -* `` +* `TimeProvider` +* `TimeProviderTaskExtensions` ## Additional Documentation - +* [API documentation](https://learn.microsoft.com/dotnet/api/system.timeprovider) -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - ## Feedback & Contributing - - Microsoft.Bcl.TimeProvider is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 8856a04e4647c2087927273475449fa6bf8b0dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cant=C3=BA?= Date: Thu, 7 Sep 2023 10:54:12 -0500 Subject: [PATCH 221/345] Add Microsoft.Extensions.Caching.Memory package.md details --- .../src/PACKAGE.md | 65 ++++++++++++++++--- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md index baa592831d4977..8798aa1ff8f38f 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md @@ -2,43 +2,88 @@ - +Provides implementations for local and distributed in-memory cache. It stores and retrieves data in a fast and efficient way. ## Key Features -* -* -* +* A concrete implementation of the IMemoryCache interface, which represents a local in-memory cache that stores and retrieves data in a fast and efficient way +* A distributed cache that supports higher scale-out than local cache +* Expiration and eviction policies for its entries +* Entry prioritization for when the cache size limit is exceeded and needs to be compacted by entry eviction +* Track of cache statictics ## How to Use +Use Microsoft.Extensions.Caching.Memory over System.Runtime.Caching when working with ASP.NET Core as it provides better integration support. For example, IMemoryCache works natively with ASP.NET Core dependency injection. + +Local in-memory serialization: +```csharp +using Microsoft.Extensions.Caching.Memory; + +using MemoryCache cache = new(new MemoryCacheOptions()); + +object valueToCache = new(); +string key = "key"; + +using (ICacheEntry entry = cache.CreateEntry(key)) +{ + // Entries are committed after they are disposed therefore it does not exist yet. + Console.WriteLine($"Exists: {cache.TryGetValue(key, out _)}\n"); + + entry.Value = valueToCache; + entry.SlidingExpiration = TimeSpan.FromSeconds(2); +} + +bool exists = cache.TryGetValue(key, out object? cachedValue); +Console.WriteLine($"Exists: {exists}" ); +Console.WriteLine($"cachedValue is valueToCache? {object.ReferenceEquals(cachedValue, valueToCache)}\n"); + +Console.WriteLine("Wait for the sliding expiration..."); +Thread.Sleep(TimeSpan.FromSeconds(2)); + +Console.WriteLine("Exists: " + cache.TryGetValue(key, out _)); + +// You can also use the acceleration extensions to set and get entries +string key2 = "key2"; +object value2 = new(); + +cache.Set("key2", value2); + +object? cachedValue2 = cache.Get(key2); +Console.WriteLine($"cachedValue2 is value2? {object.ReferenceEquals(cachedValue2, value2)}"); +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `Microsoft.Extensions.Caching.Memory.MemoryCache` +* `Microsoft.Extensions.Caching.Memory.MemoryCacheOptions` +* `Microsoft.Extensions.Caching.Distributed.MemoryDistributedCache` +* `Microsoft.Extensions.Caching.Memory.MemoryDistributedCacheOptions` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/caching) +* [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.caching.memory) ## Related Packages +[Microsoft.Extensions.Caching.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Abstractions) + ## Feedback & Contributing -Microsoft.Extensions.Caching.Memory is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Caching.Memory is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 8f4b862be53a66b76ce9836539840ffd49af6498 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 7 Sep 2023 11:10:45 -0500 Subject: [PATCH 222/345] Add Microsoft.Extensions.DependencyInjection --- .../src/PACKAGE.md | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md index dbf19733382c4d..5ebf199c4d144a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md @@ -1,44 +1,50 @@ ## About - - - - +Supports the dependency injection (DI) software design pattern which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. ## Key Features - - - -* -* -* +Provides an implementation of the DI interfaces found in the `Microsoft.Extensions.DependencyInjection.Abstractions` package. ## How to Use - - +```cs +ServiceCollection services = new (); +services.AddSingleton(); +using ServiceProvider provider = services.BuildServiceProvider(); + +// The code below, following the IoC pattern, is typically only aware of the IMessageWriter interface, not the implementation. +IMessageWriter messageWriter = provider.GetService()!; +messageWriter.Write("Hello"); + +public interface IMessageWriter +{ + void Write(string message); +} + +internal class MessageWriter : IMessageWriter +{ + public void Write(string message) + { + Console.WriteLine($"MessageWriter.Write(message: \"{message}\")"); + } +} +``` ## Main Types - - - The main types provided by this library are: - -* `` -* `` -* `` +* `Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory` +* `Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions` +* `Microsoft.Extensions.DependencyInjection.ServiceProvider` ## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection) +* API documentation + - [DefaultServiceProviderFactory](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.defaultserviceproviderfactory) + - [ServiceCollectionContainerBuilderExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectioncontainerbuilderextensions) + - [ServiceProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.serviceprovider) ## Related Packages - - +- `Microsoft.Extensions.DependencyInjection.Abstractions` +- `Microsoft.Extensions.Hosting` +- `Microsoft.Extensions.Options` ## Feedback & Contributing - - - -Microsoft.Extensions.DependencyInjection is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.DependencyInjection is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 124d40abc463a12641835537599de5bb9422e236 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 7 Sep 2023 11:58:44 -0500 Subject: [PATCH 223/345] Add Microsoft.Extensions.DependencyInjections.Abstractions --- .../src/PACKAGE.md | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md index 9ec0653cb849c6..6c8a654b7f4ff1 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/PACKAGE.md @@ -1,44 +1,34 @@ ## About - - - - +Supports the lower-level abstractions for the dependency injection (DI) software design pattern which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. ## Key Features - - - -* -* -* +- Interfaces for DI implementations which are provided in other packages including `Microsoft.Extensions.DependencyInjection`. +- An implementation of a service collection, which is used to add services to and later retrieve them either directly or through constructor injection. +- Interfaces, attributes and extensions methods to support various DI concepts including specifying a service's lifetime and supporting keyed services. ## How to Use - - +This package is typically used with an implementation of the DI abstractions, such as `Microsoft.Extensions.DependencyInjection`. ## Main Types - - - The main types provided by this library are: - -* `` -* `` -* `` +* `Microsoft.Extensions.DependencyInjection.ActivatorUtilities` +* `Microsoft.Extensions.DependencyInjection.IServiceCollection` +* `Microsoft.Extensions.DependencyInjection.ServiceCollection` +* `Microsoft.Extensions.DependencyInjection.ServiceCollectionDescriptorExtensions` +* `Microsoft.Extensions.DependencyInjection.ServiceDescriptor` +* `Microsoft.Extensions.DependencyInjection.IServiceProviderFactory` ## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/dependency-injection) +* API documentation + - [ActivatorUtilities](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.defaultserviceproviderfactory) + - [ServiceCollection](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection) + - [ServiceDescriptor](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.servicedescriptor) ## Related Packages - - +- `Microsoft.Extensions.DependencyInjection` +- `Microsoft.Extensions.Hosting` +- `Microsoft.Extensions.Options` ## Feedback & Contributing - - - -Microsoft.Extensions.DependencyInjection.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.DependencyInjection.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From a1ddb5eecdc4ac7b33c0e836dd02fe64358350bc Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 7 Sep 2023 12:55:33 -0500 Subject: [PATCH 224/345] Add Microsoft.Extensions.Hosting --- .../src/PACKAGE.md | 76 ++++++++++++------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md index 4370cde8aa3573..0887f275672ddc 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md @@ -1,44 +1,68 @@ ## About +Contains the .NET Generic Host `HostBuilder` which layers on the `Microsoft.Extensions.Hosting.Abstractions` package. - - - +A host encapsulates an app's resources and lifetime functionality, such as: +- Dependency injection (DI). +- Logging. +- Configuration. +- The `IHostedService` implementation which supports starting and stopping. ## Key Features - - - -* -* -* +* Contains the .NET Generic Host `HostBuilder`. ## How to Use - - +For a console app project: +```cs + using (IHost host = new HostBuilder().Build()) + { + var lifetime = host.Services.GetRequiredService(); + + lifetime.ApplicationStarted.Register(() => + { + Console.WriteLine("Started"); + }); + lifetime.ApplicationStopping.Register(() => + { + Console.WriteLine("Stopping firing"); + Console.WriteLine("Stopping end"); + }); + lifetime.ApplicationStopped.Register(() => + { + Console.WriteLine("Stopped firing"); + Console.WriteLine("Stopped end"); + }); + + host.Start(); + + // Listens for Ctrl-C. + host.WaitForShutdown(); + } +``` ## Main Types - - - The main types provided by this library are: - -* `` -* `` -* `` +* `Microsoft.Extensions.Host`. +* `Microsoft.Extensions.Hosting.HostApplicationBuilder` +* `Microsoft.Extensions.Hosting.HostBuilder` +* `Microsoft.Extensions.Hosting.IHostedService` +* `Microsoft.Extensions.Hosting.IHostedLifecycleService` ## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Generic host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host) +* API documentation + - [Host](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.host) + - [HostApplicationBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.hostapplicationbuilder) + - [HostBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.hostbuilder) ## Related Packages - - +- `Microsoft.Extensions.Configuration` +- `Microsoft.Extensions.DependencyInjection` +- `Microsoft.Extensions.Hosting.Abstractions` +- `Microsoft.Extensions.Logging` +- `Microsoft.Extensions.Options` ## Feedback & Contributing -Microsoft.Extensions.Hosting is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Hosting is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From eb7a5a70681fdd2028559d5e20c34f82ef8ddcb0 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Thu, 7 Sep 2023 14:33:55 -0500 Subject: [PATCH 225/345] Add Microsoft.Extensions.Hosting.WindowsServices --- .../src/PACKAGE.md | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md index e70b7da4ac046f..65908c6aaa7b63 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting.WindowsServices/src/PACKAGE.md @@ -1,44 +1,44 @@ ## About - - - - +Supports using Windows Services with the hosting infrastructure. ## Key Features - - - -* -* -* +* Can configure a host to be a Windows Service. ## How to Use - - +From a Worker Service app created using the Visual Studio template: +```cs +IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddHostedService(); + }) + // Configure as a Windows Service + .UseWindowsService(options => + { + options.ServiceName = "My Service"; + }) + .Build(); + +host.Run(); +``` ## Main Types - - - The main types provided by this library are: - -* `` -* `` -* `` +* `Microsoft.Extensions.Hosting.WindowsServiceLifetimeHostBuilderExtensions` +* `Microsoft.Extensions.Hosting.WindowsServices.WindowsServiceLifetime` ## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [WindowsServiceLifetime](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.windowsservices.windowsservicelifetime) +* [WindowsServiceLifetimeHostBuilderExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.windowsservicelifetimehostbuilderextensions) +* [Create Windows Service using BackgroundService](https://learn.microsoft.com/dotnet/core/extensions/windows-service) +* [Host ASP.NET Core in a Windows Service](https://learn.microsoft.com/aspnet/core/host-and-deploy/windows-service?tabs=visual-studio) ## Related Packages - - +- `Microsoft.Extensions.Hosting` +- `System.ServiceProcess.ServiceController` ## Feedback & Contributing -Microsoft.Extensions.Hosting.WindowsServices is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Hosting.WindowsServices is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From e343d81c15fb7989df97b958195ec36fdb8718d9 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 7 Sep 2023 13:47:14 -0700 Subject: [PATCH 226/345] Update PACKAGE.md for System.DirectoryServices --- .../System.DirectoryServices/src/PACKAGE.md | 62 +++++++++++++++---- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.DirectoryServices/src/PACKAGE.md b/src/libraries/System.DirectoryServices/src/PACKAGE.md index 2709a6e84e284f..ed4f115006da62 100644 --- a/src/libraries/System.DirectoryServices/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices/src/PACKAGE.md @@ -2,43 +2,81 @@ - +Provides easy access to [Active Directory Domain Services](https://learn.microsoft.com/windows/win32/ad/active-directory-domain-services) from managed code. `Microsoft Active Directory Domain Services` are the foundation for distributed networks built on Windows 2000 Server, Windows Server 2003 and Microsoft Windows Server 2008 operating systems that use domain controllers. The namespace contains two component classes, [DirectoryEntry](https://learn.microsoft.com/dotnet/api/system.directoryservices.directoryentry) and [DirectorySearcher](https://learn.microsoft.com/dotnet/api/system.directoryservices.directorysearcher), which use the Active Directory Services Interfaces (ADSI) technology. ADSI is the set of interfaces that Microsoft provides as a flexible tool for working with a variety of network providers. ADSI gives the administrator the ability to locate and manage resources on a network with relative ease, regardless of the size of the network. ## Key Features -* -* -* +Active Directory Domain Services use a tree structure. Each node in the tree contains a set of properties. Use this library to traverse, search, and modify the tree, and read and write to the properties of a node. + +* The [DirectoryEntry](https://learn.microsoft.com/dotnet/api/system.directoryservices.directoryentry) class encapsulates a node or object in the Active Directory Domain Services hierarchy. Use this class for binding to objects, reading properties, and updating attributes. Together with helper classes, DirectoryEntry provides support for life-cycle management and navigation methods, including creating, deleting, renaming, moving a child node, and enumerating children. +* Use the [DirectorySearcher](https://learn.microsoft.com/dotnet/api/system.directoryservices.directorysearcher) class to perform queries against the Active Directory Domain Services hierarchy. LDAP is the only system-supplied Active Directory Service Interfaces (ADSI) provider that supports searching. A search of the Active Directory Domain Services hierarchy through [DirectorySearcher](https://learn.microsoft.com/dotnet/api/system.directoryservices.directorysearcher) returns instances of [SearchResult](https://learn.microsoft.com/dotnet/api/system.directoryservices.searchresult), which are contained in an instance of the [SearchResultCollection](https://learn.microsoft.com/dotnet/api/system.directoryservices.searchresultcollection) class. +* Network administrators write scripts and applications that access Active Directory Domain Services to automate common administrative tasks, such as adding users and groups, managing printers, and setting permissions for network resources. ## How to Use +Install the `System.DirectoryServices` library from nuget + +```dotnetcli +dotnet add package System.DirectoryServices --version 7.0.1 +``` + +The sample need a real path to an Active Directory server to work properly: + +```cs +using System.DirectoryServices; + +namespace TestDirectoryServices +{ + internal class Program + { + static void Main(string[] args) + { + DirectoryEntry rootDse = new DirectoryEntry("LDAP://RootDSE"); + string configNamingContext = rootDse.Properties["configurationNamingContext"].Value.ToString(); + + DirectoryEntry certTemplates = new DirectoryEntry("LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services," + configNamingContext); + DirectorySearcher templatesSearch = new DirectorySearcher(certTemplates, "(objectClass=pKICertificateTemplate)", null, SearchScope.OneLevel); + + SearchResultCollection templates = templatesSearch.FindAll(); + + foreach (SearchResult template in templates) + { + Console.WriteLine($"Name: {template.Properties["name"][0]} ({template.Properties["displayName"][0]})"); + Console.WriteLine($"Flags: {template.Properties["msPKI-Enrollment-Flag"][0]}"); + } + } + } +} +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `System.DirectoryServices.DirectoryEntry` +* `System.DirectoryServices.DirectorySearcher` ## Additional Documentation - +* [API documentation](https://learn.microsoft.com/dotnet/api/system.directoryservices) +* [Active Directory Domain Services](https://learn.microsoft.com/windows/win32/ad/active-directory-domain-services) +* [Active Directory Service Interfaces](https://learn.microsoft.com/windows/win32/adsi/active-directory-service-interfaces-adsi) +* [Lightweight Directory Access Protocol (LDAP)](https://learn.microsoft.com/previous-versions/windows/desktop/ldap/lightweight-directory-access-protocol-ldap-api) -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) ## Related Packages - +* [System.DirectoryServices.AccountManagement](https://learn.microsoft.com/dotnet/api/system.directoryservices.accountmanagement) +* [System.DirectoryServices.Protocols](https://learn.microsoft.com/dotnet/api/system.directoryservices.protocols) ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.DirectoryServices** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From d7ad871f2bb99875de89bbedafdd0cfe4246b6ee Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 7 Sep 2023 14:32:13 -0700 Subject: [PATCH 227/345] Apply suggestions from code review --- .../Microsoft.Extensions.DependencyInjection/src/PACKAGE.md | 2 +- src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md index 5ebf199c4d144a..91474fd46a2f29 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/PACKAGE.md @@ -39,7 +39,7 @@ The main types provided by this library are: * API documentation - [DefaultServiceProviderFactory](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.defaultserviceproviderfactory) - [ServiceCollectionContainerBuilderExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectioncontainerbuilderextensions) - - [ServiceProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.serviceprovider) + - [ServiceProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.serviceprovider) ## Related Packages - `Microsoft.Extensions.DependencyInjection.Abstractions` diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md index 0887f275672ddc..f1c1084f301cdc 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md @@ -48,7 +48,7 @@ The main types provided by this library are: * `Microsoft.Extensions.Hosting.IHostedLifecycleService` ## Additional Documentation -* [Generic host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host) +* [Generic host](https://learn.microsoft.com/dotnet/core/extensions/generic-host) * API documentation - [Host](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.host) - [HostApplicationBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.hostapplicationbuilder) From 7dd0d99ae3cfe8d6fe1a9b36f7d2c0f9fa0c03b2 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 7 Sep 2023 15:57:49 -0700 Subject: [PATCH 228/345] Update System.DirectoryServices.AccountManagement PACKAGE.md --- .../src/PACKAGE.md | 55 +++++++++++++++---- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md index 2709a6e84e284f..9ca387e0757c14 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -1,44 +1,75 @@ ## About - - +Provides uniform access and manipulation of security principals across multiple principal stores. The principal objects in the Account Management API include computer, group and user objects, principal stores include: + * Active Directory Domain Services (AD DS) + * Active Directory Lightweight Directory Services (AD LDS) + * Machine SAM (MSAM). ## Key Features -* -* -* +* Basic directory operations such as creating and updating security principals. The application requires less knowledge of the underlying stores to perform these operations. +* Applications can extend the object model to include new types of directory objects. +* Account management tasks, such as enabling and disabling a user account. +* Cross-store support allows group objects in the Active Directory Domain Services (AD DS), Active Directory Lightweight Directory Services (AD LDS), and Machine SAM (MSAM) databases to contain members from different types of stores. +* Query by example searching, available on the PrincipalSearcher class, enables applications to set properties on a principal object and search the selected store for other objects that contain matching property values. +* Enhanced search on computer, user and group principal objects enables applications to search the selected store for matching principal objects. +* Recursive search, available on the group principal object, enables applications to search a group recursively and return only principal objects that are leaf nodes. +* Credential validation against the Machine SAM, AD DS, and AD LS stores. +* Connections speeds are increased by using the Fast Concurrent Bind (FSB) feature when available. Connection caching decreases the number of ports used. ## How to Use +```cs +// Create the principal context for the usr object. +PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "fabrikam.com", "CN=Users,DC=fabrikam,DC=com", "administrator", "securelyStoredPassword"); + +// Create the principal user object from the context +UserPrincipal usr = new UserPrincipal(ctx); +usr.AdvancedSearchFilter.LastLogonTime(DateTime.Now, MatchType.LessThan); +usr.AdvancedSearchFilter.LastLogonTime(DateTime.Yesterday, MatchType.GreaterThan); + +// Create a PrincipalSearcher object. +PrincipalSearcher ps = new PrincipalSearcher(usr); +PrincipalSearchResult fr = ps.FindAll(); +foreach (UserPrincipal u in results) +{ + Console.WriteLine(u.Name); +} +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `System.DirectoryServices.AccountManagement.PrincipalContext` +* `System.DirectoryServices.AccountManagement.PrincipalSearcher` +* `System.DirectoryServices.AccountManagement.Principal` and its subclasses: `System.DirectoryServices.AccountManagement.UserPrincipal`, `System.DirectoryServices.AccountManagement.GroupPrincipal` and `System.DirectoryServices.AccountManagement.ComputerPrincipal` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* Conceptual documentations: + - [System.DirectoryServices.AccountManagement Namespace Overview](https://learn.microsoft.com/en-us/previous-versions/bb384379(v=vs.90)) + - [About System.DirectoryServices.AccountManagement](https://learn.microsoft.com//previous-versions/bb384375(v=vs.90)) + - [Using System.DirectoryServices.AccountManagement](https://learn.microsoft.com/previous-versions/bb384384(v=vs.90)) +* API documentation + - [System.DirectoryServices.AccountManagement namespace](https://learn.microsoft.com/dotnet/api/system.directoryservices.accountmanagement) ## Related Packages - +[System.DirectoryServices](https://learn.microsoft.com/dotnet/api/system.directoryservices) + ## Feedback & Contributing -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.DirectoryServices.AccountManagement** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From bcb766140ee0e8dea6b28e0386547e5461ca2268 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 7 Sep 2023 16:03:00 -0700 Subject: [PATCH 229/345] Remove extra space --- .../System.DirectoryServices.AccountManagement/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md index 9ca387e0757c14..0a999337f099a4 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -1,7 +1,7 @@ ## About -Provides uniform access and manipulation of security principals across multiple principal stores. The principal objects in the Account Management API include computer, group and user objects, principal stores include: +Provides uniform access and manipulation of security principals across multiple principal stores. The principal objects in the Account Management API include computer, group and user objects, principal stores include: * Active Directory Domain Services (AD DS) * Active Directory Lightweight Directory Services (AD LDS) * Machine SAM (MSAM). From 4d0f59e74f8ebef594f770b9138dc51002d30272 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Thu, 7 Sep 2023 17:06:29 -0600 Subject: [PATCH 230/345] space --- src/libraries/System.Speech/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index 0b39583a424016..acfb0cda2ae7cc 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -33,7 +33,7 @@ synth.Speak("Hello World!"); // Speak a string asynchronously var prompt = synth.SpeakAsync("Goodnight Moon!"); -while(!prompt.IsCompleted) +while (!prompt.IsCompleted) { Console.WriteLine("speaking..."); Thread.Sleep(500); From 57a8f86490f29f5fd3bd96b0f45f9f89a4803d24 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 8 Sep 2023 09:54:36 -0500 Subject: [PATCH 231/345] Add Microsoft.Extensions.Hosting.Abstractions --- .../src/PACKAGE.md | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md index b94327b9a0078f..e699e51a601704 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md @@ -1,44 +1,43 @@ ## About +Contains abstractions to host user code in an application by encapsulating an application's resources and lifetime functionality including: +- Dependency injection (DI). +- Logging. +- Configuration. +- Starting, stopping and obtaining notifications. - - - +This package is also used to wire up specific application models like ASP.NET Core that are built on top of hosting. ## Key Features - - - -* -* -* +* Provides the `BackgroundService` base class and the `IHostedService` interface for implementing worker services. +* Provides interfaces used to configure and start\stop a host. +* Provides types to obtain environment settings such as an application name and paths. ## How to Use - - +See the Conceptual documentation below for using `BackgroundService` and `IHostedService` to host worker services. ## Main Types - - - The main types provided by this library are: -* `` -* `` -* `` +* `Microsoft.Extensions.Hosting.BackgroundService` +* `Microsoft.Extensions.Hosting.IHostBuilder` +* `Microsoft.Extensions.Hosting.IHostedService` ## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [Conceptual documentation] + - [Worker services in .NET](https://learn.microsoft.com/dotnet/core/extensions/workers) + - [Implement the IHostedService interface](https://learn.microsoft.com/dotnet/core/extensions/timer-service) +* [API documentation] + - [BackgroundService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.backgroundservice) + - [IHostBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostbuilder) + - [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) ## Related Packages - - +- `Microsoft.Extensions.Hosting` +- `Microsoft.Extensions.Configuration.Abstractions` +- `Microsoft.Extensions.DependencyInjection.Abstractions` +- `Microsoft.Extensions.Diagnostics.Abstractions` +- `Microsoft.Extensions.FileProviders.Abstractions` +- `Microsoft.Extensions.Logging.Abstractions` ## Feedback & Contributing - - - -Microsoft.Extensions.Hosting.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Hosting.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From ebf742e3655f9d72565f270a00da5e8e6be9f697 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 8 Sep 2023 09:57:35 -0500 Subject: [PATCH 232/345] Update PACKAGE.md --- src/libraries/System.DirectoryServices/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.DirectoryServices/src/PACKAGE.md b/src/libraries/System.DirectoryServices/src/PACKAGE.md index ed4f115006da62..423ed87b7f386c 100644 --- a/src/libraries/System.DirectoryServices/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices/src/PACKAGE.md @@ -24,7 +24,7 @@ Install the `System.DirectoryServices` library from nuget dotnet add package System.DirectoryServices --version 7.0.1 ``` -The sample need a real path to an Active Directory server to work properly: +The sample needs a real path to an Active Directory server to work properly: ```cs using System.DirectoryServices; From 43344fb9a7c82438eea10be00e2aac2647649308 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 8 Sep 2023 09:59:46 -0500 Subject: [PATCH 233/345] Update PACKAGE.md --- .../System.DirectoryServices.AccountManagement/src/PACKAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md index 0a999337f099a4..1cb6350eb96903 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -1,7 +1,7 @@ ## About -Provides uniform access and manipulation of security principals across multiple principal stores. The principal objects in the Account Management API include computer, group and user objects, principal stores include: +Provides uniform access and manipulation of security principals across multiple principal stores. The principal objects in the Account Management API include computer, group and user objects. The principal stores includes: * Active Directory Domain Services (AD DS) * Active Directory Lightweight Directory Services (AD LDS) * Machine SAM (MSAM). @@ -28,7 +28,7 @@ Provides uniform access and manipulation of security principals across multiple // Create the principal context for the usr object. PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "fabrikam.com", "CN=Users,DC=fabrikam,DC=com", "administrator", "securelyStoredPassword"); -// Create the principal user object from the context +// Create the principal user object from the context. UserPrincipal usr = new UserPrincipal(ctx); usr.AdvancedSearchFilter.LastLogonTime(DateTime.Now, MatchType.LessThan); usr.AdvancedSearchFilter.LastLogonTime(DateTime.Yesterday, MatchType.GreaterThan); From 56c8b145855282eb585363d3c36da11a411e7528 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 8 Sep 2023 10:02:00 -0500 Subject: [PATCH 234/345] Update Hosting --- src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md index f1c1084f301cdc..8434c4227716c1 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md @@ -1,12 +1,6 @@ ## About Contains the .NET Generic Host `HostBuilder` which layers on the `Microsoft.Extensions.Hosting.Abstractions` package. -A host encapsulates an app's resources and lifetime functionality, such as: -- Dependency injection (DI). -- Logging. -- Configuration. -- The `IHostedService` implementation which supports starting and stopping. - ## Key Features * Contains the .NET Generic Host `HostBuilder`. From 505ac8073a61170c9f3880d6b80d46bd2c4ccebf Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 8 Sep 2023 10:03:03 -0500 Subject: [PATCH 235/345] Update Hosting --- src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md index 8434c4227716c1..a9cd4f5727700b 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md @@ -28,7 +28,7 @@ For a console app project: host.Start(); - // Listens for Ctrl-C. + // Listens for Ctrl+C. host.WaitForShutdown(); } ``` From 86b9aa5dcdfa9efc94e3db284ff7c07986d0126c Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 8 Sep 2023 09:27:53 -0700 Subject: [PATCH 236/345] Remove unnecessary brackets --- .../Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md index e699e51a601704..f017c0b7193271 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/PACKAGE.md @@ -23,10 +23,10 @@ The main types provided by this library are: * `Microsoft.Extensions.Hosting.IHostedService` ## Additional Documentation -* [Conceptual documentation] +* Conceptual documentation - [Worker services in .NET](https://learn.microsoft.com/dotnet/core/extensions/workers) - [Implement the IHostedService interface](https://learn.microsoft.com/dotnet/core/extensions/timer-service) -* [API documentation] +* API documentation - [BackgroundService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.backgroundservice) - [IHostBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostbuilder) - [IHostedService](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.ihostedservice) From ae6f006aa404b99d0bdbeca879b74343d1404268 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 8 Sep 2023 11:11:33 -0600 Subject: [PATCH 237/345] add oledb and odbc --- src/libraries/System.Data.Odbc/src/PACKAGE.md | 49 +++++++++--------- .../System.Data.OleDb/src/PACKAGE.md | 51 ++++++++++--------- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md index 2709a6e84e284f..eac97dd7247198 100644 --- a/src/libraries/System.Data.Odbc/src/PACKAGE.md +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -1,44 +1,47 @@ ## About - - - +This package implements a data provider for ODBC data sources. ## Key Features - - -* -* -* +Allows access to legacy ODBC data sources. ## How to Use - +This is a basic example of retrieving the results of a query using an `OdbcDataReader`. For examples of using an `OdbcDataAdapter`, and of updating an ODBC data source, please see the documentation. -## Main Types +```cs +string queryString = "SELECT DISTINCT CustomerID FROM Orders"; +using (OdbcConnection connection = new OdbcConnection(connectionString)) +{ + OdbcCommand command = new OdbcCommand(queryString, connection); + connection.Open(); + OdbcDataReader reader = command.ExecuteReader(); - + while (reader.Read()) + { + Console.WriteLine("CustomerID={0}", reader[0]); + } -The main types provided by this library are: + reader.Close(); +} +``` -* `` -* `` -* `` +## Main Types -## Additional Documentation +* `OdbcDataAdapter` represents a set of data commands and a database connection that are used to fill a `DataSet` and update the ODBC data source. +* `OdbcDataReader` provides a way of reading a forward-only stream of data rows from an ODBC data source. +* `OdbcCommand` represents an SQL statement or stored procedure to execute against an ODBC data source.. +* `OdbcConnection` represents an open connection to an ODBC data source. - +## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.data.odbc) ## Related Packages - +System.Data.OleDb is a similar package for accessing OLE DB data sources. ## Feedback & Contributing - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Data.Odbc** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider lower-risk or high-impact fixes that will maintain or improve quality. \ No newline at end of file diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md index 2709a6e84e284f..b74dfad019759f 100644 --- a/src/libraries/System.Data.OleDb/src/PACKAGE.md +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -1,44 +1,47 @@ ## About - - - +This package implements a data provider for OLE DB data sources. ## Key Features - - -* -* -* +Allows access to legacy OLE DB data sources. ## How to Use - +This is a basic example of retrieving the results of a query using an `OleDbDataReader`. For examples of using an `OleDbDataAdapter`, and of updating an OLE DB data source, please see the documentation. + +```cs +string queryString = "SELECT OrderID, CustomerID FROM Orders"; +using (OleDbConnection connection = new OleDbConnection(connectionString)) +{ + OleDbCommand command = new OleDbCommand(queryString, connection); + connection.Open(); + OleDbDataReader reader = command.ExecuteReader(); + + while (reader.Read()) + { + Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1)); + } + // always call Close when done reading. + reader.Close(); +} +``` ## Main Types - - -The main types provided by this library are: - -* `` -* `` -* `` +* `OleDbDataAdapter` represents a set of data commands and a database connection that are used to fill a `DataSet` and update the OLE DB data source. +* `OleDbDataReader` provides a way of reading a forward-only stream of data rows from an OLE DB data source. +* `OleDbCommand` represents an SQL statement or stored procedure to execute against an OLE DB data source. +* `OleDbConnection` represents an open connection to an OLE DB data source. ## Additional Documentation - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.data.oledb) ## Related Packages - +System.Data.Odbc is a similar package for accessing ODBC data sources. ## Feedback & Contributing - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +**System.Data.OleDb** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider lower-risk or high-impact fixes that will maintain or improve quality. \ No newline at end of file From 0f8464ca3319b0250cc0525c3259ceaceaad4ec4 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 8 Sep 2023 11:15:26 -0600 Subject: [PATCH 238/345] tweak --- src/libraries/System.Data.Odbc/src/PACKAGE.md | 2 +- src/libraries/System.Data.OleDb/src/PACKAGE.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md index eac97dd7247198..7f5d22258dbc85 100644 --- a/src/libraries/System.Data.Odbc/src/PACKAGE.md +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -44,4 +44,4 @@ System.Data.OleDb is a similar package for accessing OLE DB data sources. ## Feedback & Contributing -**System.Data.Odbc** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider lower-risk or high-impact fixes that will maintain or improve quality. \ No newline at end of file +**System.Data.Odbc** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider low-risk, high-impact fixes that are necessary to maintain or improve quality. \ No newline at end of file diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md index b74dfad019759f..5d5b0649345ce2 100644 --- a/src/libraries/System.Data.OleDb/src/PACKAGE.md +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -22,7 +22,7 @@ using (OleDbConnection connection = new OleDbConnection(connectionString)) { Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1)); } - // always call Close when done reading. + reader.Close(); } ``` @@ -44,4 +44,4 @@ System.Data.Odbc is a similar package for accessing ODBC data sources. ## Feedback & Contributing -**System.Data.OleDb** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider lower-risk or high-impact fixes that will maintain or improve quality. \ No newline at end of file +**System.Data.OleDb** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider low-risk, high-impact fixes that are necessary to maintain or improve quality. \ No newline at end of file From 9bf79ce9d41c2cbeb18c1693607533fa9af78f51 Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 8 Sep 2023 13:26:15 -0600 Subject: [PATCH 239/345] Update src/libraries/System.Speech/src/PACKAGE.md Co-authored-by: MSDN.WhiteKnight <35516665+MSDN-WhiteKnight@users.noreply.github.com> --- src/libraries/System.Speech/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index acfb0cda2ae7cc..c58da5834d1b34 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -3,7 +3,7 @@ Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other non-Windows platforms. -This package is provided primarily for compatibility with code being ported from .NETFramework and is not accepting new features. +This package is provided primarily for compatibility with code being ported from .NET Framework and is not accepting new features. ## Key Features From 066cadeaa21f7c245bf5e4132dd14f5300136acd Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 8 Sep 2023 13:26:56 -0600 Subject: [PATCH 240/345] Update src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md Co-authored-by: Anton Firszov --- src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md index bf1cc0ef79e7e2..15fc9683b87abd 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md @@ -10,7 +10,7 @@ * The package allows to fluently set up multiple `HttpClient` configurations for applications that use DI via `AddHttpClient` extension method. * `HttpClientFactory` caches `HttpMessageHandler` instances per configuration name, which allows to reuse resources between `HttpClient` instances to avoid port exhaustion. -* `HttpClientFactory` manages lifetime of `HttpMessageHandler` instances and recycles connections to avoid losing DNS changes. +* `HttpClientFactory` manages lifetime of `HttpMessageHandler` instances and recycles connections to track DNS changes. ## How to Use From f5e2b2541741599fa807fde12f38d36122cbc27a Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 8 Sep 2023 13:29:14 -0600 Subject: [PATCH 241/345] Update src/libraries/System.Speech/src/PACKAGE.md --- src/libraries/System.Speech/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index c58da5834d1b34..4d2a8df1f1f8e4 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -1,7 +1,7 @@ ## About -Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other non-Windows platforms. +Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other platforms. This package is provided primarily for compatibility with code being ported from .NET Framework and is not accepting new features. From 646b0f0250262cba5462f923839296b9d3819aec Mon Sep 17 00:00:00 2001 From: Dan Moseley Date: Fri, 8 Sep 2023 14:49:07 -0600 Subject: [PATCH 242/345] Apply suggestions from code review Co-authored-by: Shay Rojansky --- src/libraries/System.Data.Odbc/src/PACKAGE.md | 30 +++++++++---------- .../System.Data.OleDb/src/PACKAGE.md | 28 ++++++++--------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md index 7f5d22258dbc85..4211f7f44ee1e5 100644 --- a/src/libraries/System.Data.Odbc/src/PACKAGE.md +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -4,35 +4,33 @@ This package implements a data provider for ODBC data sources. ## Key Features -Allows access to legacy ODBC data sources. +Allows access to ODBC data sources. ## How to Use -This is a basic example of retrieving the results of a query using an `OdbcDataReader`. For examples of using an `OdbcDataAdapter`, and of updating an ODBC data source, please see the documentation. +This is a basic example of retrieving the results of a query using an [OdbcDataReader](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcdatareader). For examples of using an [OdbcDataAdapter](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcdataadapter), and of updating an ODBC data source, please see the documentation. ```cs string queryString = "SELECT DISTINCT CustomerID FROM Orders"; -using (OdbcConnection connection = new OdbcConnection(connectionString)) -{ - OdbcCommand command = new OdbcCommand(queryString, connection); - connection.Open(); - OdbcDataReader reader = command.ExecuteReader(); - while (reader.Read()) - { - Console.WriteLine("CustomerID={0}", reader[0]); - } +using OdbcConnection connection = new OdbcConnection(connectionString); +using OdbcCommand command = new OdbcCommand(queryString, connection); + +connection.Open(); +using OdbcDataReader reader = command.ExecuteReader(); - reader.Close(); +while (reader.Read()) +{ + Console.WriteLine("CustomerID={0}", reader[0]); } ``` ## Main Types -* `OdbcDataAdapter` represents a set of data commands and a database connection that are used to fill a `DataSet` and update the ODBC data source. -* `OdbcDataReader` provides a way of reading a forward-only stream of data rows from an ODBC data source. -* `OdbcCommand` represents an SQL statement or stored procedure to execute against an ODBC data source.. -* `OdbcConnection` represents an open connection to an ODBC data source. +* [OdbcConnection](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcconnection) represents a connection to an ODBC data source. +* [OdbcCommand](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbccommand) represents an SQL statement or stored procedure to execute against an ODBC data source.. +* [OdbcDataReader](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcdatareader) provides a way of reading a forward-only stream of data rows from an ODBC data source. +* [OdbcDataAdapter](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcdataadapter) represents a set of data commands and a database connection that are used to fill a [DataSet](https://learn.microsoft.com/dotnet/api/system.data.dataset) and update the ODBC data source. ## Additional Documentation diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md index 5d5b0649345ce2..85b73459db6794 100644 --- a/src/libraries/System.Data.OleDb/src/PACKAGE.md +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -8,31 +8,29 @@ Allows access to legacy OLE DB data sources. ## How to Use -This is a basic example of retrieving the results of a query using an `OleDbDataReader`. For examples of using an `OleDbDataAdapter`, and of updating an OLE DB data source, please see the documentation. +This is a basic example of retrieving the results of a query using an [OleDbDataReader](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbdatareader). For examples of using an [OleDbDataAdapter](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbdataadapter), and of updating an OLE DB data source, please see the documentation. ```cs string queryString = "SELECT OrderID, CustomerID FROM Orders"; -using (OleDbConnection connection = new OleDbConnection(connectionString)) -{ - OleDbCommand command = new OleDbCommand(queryString, connection); - connection.Open(); - OleDbDataReader reader = command.ExecuteReader(); - while (reader.Read()) - { - Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1)); - } +using OleDbConnection connection = new OleDbConnection(connectionString); +using OleDbCommand command = new OleDbCommand(queryString, connection); + +connection.Open(); +using OleDbDataReader reader = command.ExecuteReader(); - reader.Close(); +while (reader.Read()) +{ + Console.WriteLine(reader.GetInt32(0) + ", " + reader.GetString(1)); } ``` ## Main Types -* `OleDbDataAdapter` represents a set of data commands and a database connection that are used to fill a `DataSet` and update the OLE DB data source. -* `OleDbDataReader` provides a way of reading a forward-only stream of data rows from an OLE DB data source. -* `OleDbCommand` represents an SQL statement or stored procedure to execute against an OLE DB data source. -* `OleDbConnection` represents an open connection to an OLE DB data source. +* [OleDbConnection](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbconnection) represents an open connection to an OLE DB data source. +* [OleDbCommand](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbcommand) represents an SQL statement or stored procedure to execute against an OLE DB data source. +* [OleDbDataReader](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbdatareader) provides a way of reading a forward-only stream of data rows from an OLE DB data source. +* [OleDbDataAdapter](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbdataadapter) represents a set of data commands and a database connection that are used to fill a `DataSet` and update the OLE DB data source. ## Additional Documentation From f107d058fb9f597231f50e56a57ac37ad0837a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 11 Sep 2023 08:44:36 -0600 Subject: [PATCH 243/345] Apply suggestions for System.Diagnostics.EventLog & PerformanceCounter --- .../src/PACKAGE.md | 46 +++---------------- .../src/PACKAGE.md | 22 ++------- 2 files changed, 10 insertions(+), 58 deletions(-) diff --git a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md index 1cb7eae3a470b3..2821a14f7c70b0 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md @@ -2,9 +2,9 @@ -When an error occurs in a Windows machine, the system administrator or support representative must determine what caused the error, attempt to recover any lost data, and prevent the error from recurring. It is helpful if applications, the operating system, and other system services record important events, such as low-memory conditions or excessive attempts to access a disk. The system administrator can then use the Windows Event Log to help determine what conditions caused the error and identify the context in which it occurred. +This package provides types that allow applications to interact with the Windows Event Log service. -This package provides the `System.Diagnostics.EventLog.dll` assembly, which contains types that allow applications to interact with the Windows Event Log service. +When an error occurs in a Windows machine, the system administrator or support representative must determine what caused the error, attempt to recover any lost data, and prevent the error from recurring. It is helpful if applications, the operating system, and other system services record important events, such as low-memory conditions or excessive attempts to access a disk. The system administrator can then use the Windows Event Log to help determine what conditions caused the error and identify the context in which it occurred. ## Key Features @@ -50,55 +50,21 @@ Notes: The main types provided by this library are: -Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace: +Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace, the main types are: -- [`System.Diagnostics.EntryWrittenEventArgs`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EntryWrittenEventArgs) -- [`System.Diagnostics.EntryWrittenEventHandler`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EntryWrittenEventHandler) -- [`System.Diagnostics.EventInstance`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventInstance) - [`System.Diagnostics.EventLog`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLog) - [`System.Diagnostics.EventLogEntry`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntry) - [`System.Diagnostics.EventLogEntryCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntryCollection) - [`System.Diagnostics.EventLogEntryType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntryType) -- [`System.Diagnostics.EventLogTraceListener`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogTraceListener) -- [`System.Diagnostics.EventSourceCreationData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventSourceCreationData) -- [`System.Diagnostics.OverflowAction`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.OverflowAction) - -Under the[`System.Diagnostics.Eventing.Reader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader) namespace: - -- [`System.Diagnostics.Eventing.Reader.EventBookmark`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventBookmark) -- [`System.Diagnostics.Eventing.Reader.EventKeyword`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventKeyword) -- [`System.Diagnostics.Eventing.Reader.EventLevel`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLevel) -- [`System.Diagnostics.Eventing.Reader.EventLogConfiguration`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogConfiguration) -- [`System.Diagnostics.Eventing.Reader.EventLogException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogException) -- [`System.Diagnostics.Eventing.Reader.EventLogInformation`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogInformation) -- [`System.Diagnostics.Eventing.Reader.EventLogInvalidDataException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogInvalidDataException) -- [`System.Diagnostics.Eventing.Reader.EventLogIsolation`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogIsolation) -- [`System.Diagnostics.Eventing.Reader.EventLogLink`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogLink) -- [`System.Diagnostics.Eventing.Reader.EventLogMode`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogMode) -- [`System.Diagnostics.Eventing.Reader.EventLogNotFoundException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogNotFoundException) -- [`System.Diagnostics.Eventing.Reader.EventLogPropertySelector`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogPropertySelector) -- [`System.Diagnostics.Eventing.Reader.EventLogProviderDisabledException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogProviderDisabledException) + +Under the [`System.Diagnostics.Eventing.Reader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader) namespace, the main types are: + - [`System.Diagnostics.Eventing.Reader.EventLogQuery`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogQuery) - [`System.Diagnostics.Eventing.Reader.EventLogReader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogReader) -- [`System.Diagnostics.Eventing.Reader.EventLogReadingException`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogReadingException) - [`System.Diagnostics.Eventing.Reader.EventLogRecord`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogRecord) - [`System.Diagnostics.Eventing.Reader.EventLogSession`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogSession) -- [`System.Diagnostics.Eventing.Reader.EventLogStatus`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogStatus) - [`System.Diagnostics.Eventing.Reader.EventLogType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogType) -- [`System.Diagnostics.Eventing.Reader.EventLogWatcher`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogWatcher) -- [`System.Diagnostics.Eventing.Reader.EventMetadata`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventMetadata) -- [`System.Diagnostics.Eventing.Reader.EventOpcode`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventOpcode) -- [`System.Diagnostics.Eventing.Reader.EventProperty`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventProperty) - [`System.Diagnostics.Eventing.Reader.EventRecord`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventRecord) -- [`System.Diagnostics.Eventing.Reader.EventRecordWrittenEventArgs`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventRecordWrittenEventArgs) -- [`System.Diagnostics.Eventing.Reader.EventTask`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventTask) -- [`System.Diagnostics.Eventing.Reader.PathType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.PathType) -- [`System.Diagnostics.Eventing.Reader.ProviderMetadata`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.ProviderMetadata) -- [`System.Diagnostics.Eventing.Reader.SessionAuthentication`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.SessionAuthentication) -- [`System.Diagnostics.Eventing.Reader.StandardEventKeywords`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventKeywords) -- [`System.Diagnostics.Eventing.Reader.StandardEventLevel`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventLevel) -- [`System.Diagnostics.Eventing.Reader.StandardEventOpcode`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventOpcode) -- [`System.Diagnostics.Eventing.Reader.StandardEventTask`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.StandardEventTask) ## Additional Documentation diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md index 1fecb16e569611..6f74c9a86379c6 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md @@ -2,14 +2,14 @@ +This package provides types that allow applications to interact with the Windows performance counters. + Windows allows you to examine how programs you run affect your computer's performance, both in real time and by collecting log data for later analysis. You can do this via the Windows Performance Monitor tool, which uses performance counters, among other features. Windows performance counters provide a high-level abstraction layer that provides a consistent interface for collecting various kinds of system data such as CPU, memory, and disk usage. They can be included in the operating system or can be part of individual applications. Windows Performance Monitor requests the current value of performance counters at specifiedtime intervals. System administrators often use performance counters to monitor systems for performance or behavior problems. Software developers often use performance counters to examine the resource usage of their programs. -This package provides the `System.Diagnostics.PerformanceCounter.dll` assembly, which contains types that allow applications to interact with the Windows performance counters. - ## Key Features @@ -188,30 +188,16 @@ Notes: The main types provided by this library are: -Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace: +Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace, the main types are: * [`System.Diagnostics.CounterCreationData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterCreationData) * [`System.Diagnostics.CounterCreationDataCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterCreationDataCollection) -* [`System.Diagnostics.CounterSample`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterSample) -* [`System.Diagnostics.CounterSampleCalculator`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterSampleCalculator) -* [`System.Diagnostics.ICollectData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.ICollectData) -* [`System.Diagnostics.InstanceData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.InstanceData) -* [`System.Diagnostics.InstanceDataCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.InstanceDataCollection) -* [`System.Diagnostics.InstanceDataCollectionCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.InstanceDataCollectionCollection) * [`System.Diagnostics.PerformanceCounter`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounter) -* [`System.Diagnostics.PerformanceCounterCategory`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterCategory) -* [`System.Diagnostics.PerformanceCounterCategoryType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterCategoryType) -* [`System.Diagnostics.PerformanceCounterInstanceLifetime`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterInstanceLifetime) -* [`System.Diagnostics.PerformanceCounterManager`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterManager) -* [`System.Diagnostics.PerformanceCounterType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounterType) -Under the [`System.Diagnostics.PerformanceData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData) namespace: +Under the [`System.Diagnostics.PerformanceData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData) namespace, the main types are: * [`System.Diagnostics.PerformanceData.CounterData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterData) * [`System.Diagnostics.PerformanceData.CounterSet`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSet) -* [`System.Diagnostics.PerformanceData.CounterSetInstance`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSetInstance) -* [`System.Diagnostics.PerformanceData.CounterSetInstanceCounterDataSet`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSetInstanceCounterDataSet) -* [`System.Diagnostics.PerformanceData.CounterSetInstanceType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSetInstanceType) * [`System.Diagnostics.PerformanceData.CounterType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterType) ## Additional Documentation From eca1ff8ec64ff6e053008a2afb14ad49519fb0fc Mon Sep 17 00:00:00 2001 From: Michael Sharp Date: Tue, 12 Sep 2023 23:13:22 -0600 Subject: [PATCH 244/345] added Bcl.Numerics --- .../Microsoft.Bcl.Numerics/src/PACKAGE.md | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md index df05c1c906d9b8..faa3594f73e151 100644 --- a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md @@ -1,20 +1,32 @@ ## About - - - +As of .NET Core 2.0 and .NET Standard 2.1, the C# language has support for math (System.MathF) functions with floats. This library provides the necessary definitions of those types to support these language features on .NET Framework and on .NET Standard 2.0. This library is not necessary nor recommended when targeting versions of .NET that include the relevant support. ## Key Features -* -* -* +* Enables the use of MathF on older .NET platforms + ## How to Use - +```C# +using System; +using System.MathF. + +internal static class Program +{ + private static async Task Main() + { + Console.WriteLine("Starting..."); + + Console.WriteLine(MathF.Max(1f, 5f)); // returns 5f + + Console.WriteLine("Finished!"); + } +} +``` ## Main Types @@ -22,20 +34,13 @@ The main types provided by this library are: -* `` -* `` -* `` +* `System.MathF` ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - +* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.mathf) ## Feedback & Contributing From 5827567812b4a3b4d9a60edd068d0518459872ae Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Sat, 16 Sep 2023 12:20:41 -0700 Subject: [PATCH 245/345] Fill template for Microsoft.Extensions.Configuration & Abstractions --- .../src/PACKAGE.md | 30 +++++++---- .../src/PACKAGE.md | 52 ++++++++++++++++--- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md index fb051d69f251b2..bf951fcc17968e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md @@ -4,13 +4,15 @@ Provides abstractions of key-value pair based configuration. Interfaces defined in this package are implemented by classes in [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and other configuration packages. + ## Key Features -* -* -* +* Abstractions for string key-value pair configuration sources and sections +* Path conventions of keys establishing a heirachy of values +* Support for multiple configuration sources, aggregating and defining precdence for values +* Support for reload on change ## How to Use @@ -42,17 +44,18 @@ var options = config.Get(); Console.WriteLine(options.NamedProperty); // returns "value for named property" ``` + ## Main Types The main types provided by this library are: -* [`Microsoft.Extensions.Configuration.IConfiguration`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfiguration) -* [`Microsoft.Extensions.Configuration.IConfigurationBuilder`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationbuilder) -* [`Microsoft.Extensions.Configuration.IConfigurationProvider`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationprovider) -* [`Microsoft.Extensions.Configuration.IConfigurationRoot`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationroot) -* [`Microsoft.Extensions.Configuration.IConfigurationSection`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iconfigurationsection) +* `Microsoft.Extensions.Configuration.IConfiguration` +* `Microsoft.Extensions.Configuration.IConfigurationBuilder` +* `Microsoft.Extensions.Configuration.IConfigurationProvider` +* `Microsoft.Extensions.Configuration.IConfigurationRoot` +* `Microsoft.Extensions.Configuration.IConfigurationSection` ## Additional Documentation @@ -64,9 +67,18 @@ The main types provided by this library are: ## Related Packages +* [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) +* [Microsoft.Extensions.Configuration.Binder](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Binder) +* [Microsoft.Extensions.Configuration.CommandLine](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.CommandLine) +* [Microsoft.Extensions.Configuration.EnvironmentVariables](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.EnvironmentVariables) +* [Microsoft.Extensions.Configuration.FileExtensions](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.FileExtensions) +* [Microsoft.Extensions.Configuration.Ini](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Ini) +* [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json) +* [Microsoft.Extensions.Configuration.UserSecrets](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets) +* [Microsoft.Extensions.Configuration.Xml](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Xml) ## Feedback & Contributing -Microsoft.Extensions.Configuration.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Caching.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md index 13f09693b243a3..b9f3878b7e9b78 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md @@ -8,13 +8,41 @@ -* -* -* +* In-memory configuration provider +* Chained configuration provider for chaining multiple confiugration providers together. +* Base types that implement configuration abstraction interfaces that can be used when implementing other configuration providers. ## How to Use +```C# +using Microsoft.Extensions.Configuration; + +var configurationBuilder = new ConfigurationBuilder(); + +configurationBuilder.AddInMemoryCollection( + new Dictionary + { + ["Setting1"] = "value", + ["MyOptions:Enabled"] = bool.TrueString, + }); + +configurationBuilder.AddInMemoryCollection( + new Dictionary + { + ["Setting2"] = "value2", + ["MyOptions:Enabled"] = bool.FalseString, + }); + +var config = configurationBuilder.Build(); + +// note case-insensitive +Console.WriteLine(config["setting1"]); +Console.WriteLine(config["setting2"]); + +// note last in wins +Console.WriteLine(config["MyOptions:Enabled"]); +``` ## Main Types @@ -22,9 +50,10 @@ The main types provided by this library are: -* `` -* `` -* `` +* `Microsoft.Extensions.Configuration.ConfigurationBuilder` +* `Microsoft.Extensions.Configuration.ConfigurationManager` +* `Microsoft.Extensions.Configuration.ConfigurationRoot` +* `Microsoft.Extensions.Configuration.ConfigurationSection` ## Additional Documentation @@ -36,9 +65,18 @@ The main types provided by this library are: ## Related Packages +* [Microsoft.Extensions.Configuration.Binder](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Binder) +* [Microsoft.Extensions.Configuration.CommandLine](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.CommandLine) +* [Microsoft.Extensions.Configuration.EnvironmentVariables](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.EnvironmentVariables) +* [Microsoft.Extensions.Configuration.FileExtensions](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.FileExtensions) +* [Microsoft.Extensions.Configuration.Ini](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Ini) +* [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json) +* [Microsoft.Extensions.Configuration.UserSecrets](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets) +* [Microsoft.Extensions.Configuration.Xml](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Xml) + ## Feedback & Contributing -Microsoft.Extensions.Configuration is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Configuration is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From cf124a103629a29295fe16c40fc72d0ad72f3f54 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Sat, 16 Sep 2023 12:46:24 -0700 Subject: [PATCH 246/345] Add Microsoft.Extensions.Configuration.Binder readme. --- .../src/PACKAGE.md | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md index f39973daaad6f2..c7caaacac6c1c4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md @@ -4,13 +4,15 @@ Provides the functionality to bind an object to data in configuration providers for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to represent the configuration data as strongly-typed classes defined in the application code. To bind a configuration, use the [Microsoft.Extensions.Configuration.ConfigurationBinder.Get](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.configurationbinder.get) extension method on the `IConfiguration` object. To use this package, you also need to install a package for the [configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration#configuration-providers), for example, [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json/) for the JSON provider. +The types contained in this assembly use Reflection at runtime which is not friendly with linking or AOT. To better support linking and AOT as well as provide more efficient strongly-typed binding methods - this package also provides a source generator. This generator is enabled by default when a project sets `PublishAot` but can also be enabled using `true`. + ## Key Features -* -* -* +* Configuring existing type instances from a configuration section (Bind) +* Constructing new configured type instances from a configuration section (Get & GetValue) +* Generating source to bind objects from a configuration section without a runtime reflection dependency. ## How to Use @@ -53,7 +55,7 @@ class Program // Read nested objects Console.WriteLine("Endpoints: "); - + foreach (Endpoint endpoint in settings.Endpoints) { Console.WriteLine($"{endpoint.IPAddress}:{endpoint.Port}"); @@ -93,15 +95,21 @@ You can include a configuration file using a code like this in your `.csproj` fi ``` +You can add the following property to enable the source generator. This requires a .NET 8.0 SDK or later. +```xml + + true + +``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `Microsoft.Extensions.Configuration.ConfigurationBinder` +* `Microsoft.Extensions.Configuration.BinderOptions` ## Additional Documentation @@ -113,9 +121,18 @@ The main types provided by this library are: ## Related Packages +* [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration) +* [Microsoft.Extensions.Configuration.Abstractions](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Abstractions) +* [Microsoft.Extensions.Configuration.CommandLine](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.CommandLine) +* [Microsoft.Extensions.Configuration.EnvironmentVariables](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.EnvironmentVariables) +* [Microsoft.Extensions.Configuration.FileExtensions](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.FileExtensions) +* [Microsoft.Extensions.Configuration.Ini](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Ini) +* [Microsoft.Extensions.Configuration.Json](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Json) +* [Microsoft.Extensions.Configuration.UserSecrets](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets) +* [Microsoft.Extensions.Configuration.Xml](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Xml) ## Feedback & Contributing -Microsoft.Extensions.Configuration.Binder is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +Microsoft.Extensions.Configuration.Binder is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 3eba320f1ea303ce574fdda14742d67196522814 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:14:49 +0200 Subject: [PATCH 247/345] Remove undocumented P2 package readmes --- .../Microsoft.Bcl.Cryptography/src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- src/libraries/System.CodeDom/src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../System.Composition.Hosting/src/PACKAGE.md | 44 ------------------- .../System.Composition.Runtime/src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../System.Composition/src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../System.Drawing.Common/src/PACKAGE.md | 44 ------------------- .../System.Formats.Cbor/src/PACKAGE.md | 44 ------------------- .../System.IO.Hashing/src/PACKAGE.md | 44 ------------------- .../System.IO.Packaging/src/PACKAGE.md | 44 ------------------- .../System.IO.Pipelines/src/PACKAGE.md | 44 ------------------- .../System.Management/src/PACKAGE.md | 44 ------------------- .../System.Memory.Data/src/PACKAGE.md | 44 ------------------- .../System.Numerics.Tensors/src/PACKAGE.md | 44 ------------------- .../System.Reflection.Context/src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../System.Text.Encodings.Web/src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- .../src/PACKAGE.md | 44 ------------------- src/libraries/System.Threading/src/PACKAGE.md | 44 ------------------- .../System.Windows.Extensions/src/PACKAGE.md | 44 ------------------- 52 files changed, 2288 deletions(-) delete mode 100644 src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md delete mode 100644 src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md delete mode 100644 src/libraries/System.CodeDom/src/PACKAGE.md delete mode 100644 src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md delete mode 100644 src/libraries/System.ComponentModel.Composition/src/PACKAGE.md delete mode 100644 src/libraries/System.Composition.AttributedModel/src/PACKAGE.md delete mode 100644 src/libraries/System.Composition.Convention/src/PACKAGE.md delete mode 100644 src/libraries/System.Composition.Hosting/src/PACKAGE.md delete mode 100644 src/libraries/System.Composition.Runtime/src/PACKAGE.md delete mode 100644 src/libraries/System.Composition.TypedParts/src/PACKAGE.md delete mode 100644 src/libraries/System.Composition/src/PACKAGE.md delete mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md delete mode 100644 src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md delete mode 100644 src/libraries/System.Drawing.Common/src/PACKAGE.md delete mode 100644 src/libraries/System.Formats.Cbor/src/PACKAGE.md delete mode 100644 src/libraries/System.IO.Hashing/src/PACKAGE.md delete mode 100644 src/libraries/System.IO.Packaging/src/PACKAGE.md delete mode 100644 src/libraries/System.IO.Pipelines/src/PACKAGE.md delete mode 100644 src/libraries/System.Management/src/PACKAGE.md delete mode 100644 src/libraries/System.Memory.Data/src/PACKAGE.md delete mode 100644 src/libraries/System.Numerics.Tensors/src/PACKAGE.md delete mode 100644 src/libraries/System.Reflection.Context/src/PACKAGE.md delete mode 100644 src/libraries/System.Resources.Extensions/src/PACKAGE.md delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md delete mode 100644 src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md delete mode 100644 src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md delete mode 100644 src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md delete mode 100644 src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md delete mode 100644 src/libraries/System.Security.Permissions/src/PACKAGE.md delete mode 100644 src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md delete mode 100644 src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md delete mode 100644 src/libraries/System.Text.Encodings.Web/src/PACKAGE.md delete mode 100644 src/libraries/System.Threading.AccessControl/src/PACKAGE.md delete mode 100644 src/libraries/System.Threading.RateLimiting/src/PACKAGE.md delete mode 100644 src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md delete mode 100644 src/libraries/System.Threading/src/PACKAGE.md delete mode 100644 src/libraries/System.Windows.Extensions/src/PACKAGE.md diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md deleted file mode 100644 index 5a3a8c037bca45..00000000000000 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Bcl.Cryptography is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md deleted file mode 100644 index 651e3c04c98405..00000000000000 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Caching.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md deleted file mode 100644 index 79b5aea01302e5..00000000000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Specification.Tests/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.DependencyInjection.Specification.Tests is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md deleted file mode 100644 index efb7ca7c9133cc..00000000000000 --- a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.FileProviders.Abstractions is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md deleted file mode 100644 index 122fbecfa2ba91..00000000000000 --- a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.FileProviders.Composite is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md deleted file mode 100644 index bf3378a56e63dd..00000000000000 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.FileProviders.Physical is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md deleted file mode 100644 index a5d26b28318fda..00000000000000 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.FileSystemGlobbing is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md deleted file mode 100644 index ffb5501c8568fe..00000000000000 --- a/src/libraries/Microsoft.Extensions.Hosting.Systemd/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Hosting.Systemd is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md deleted file mode 100644 index 7c38fc44d350f7..00000000000000 --- a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Logging.Configuration is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md deleted file mode 100644 index 9f1330aad75f6a..00000000000000 --- a/src/libraries/Microsoft.Extensions.Logging.EventLog/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Logging.EventLog is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md deleted file mode 100644 index 8a67a2888f46db..00000000000000 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Logging.EventSource is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md deleted file mode 100644 index 7bab863fa95cc9..00000000000000 --- a/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Logging.TraceSource is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md deleted file mode 100644 index 3bf3280ad4cf1b..00000000000000 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -Microsoft.Extensions.Options.DataAnnotations is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md b/src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/Microsoft.NET.WebAssembly.Threading/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md b/src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/Microsoft.Win32.Registry.AccessControl/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md b/src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md b/src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/Microsoft.XmlSerializer.Generator/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.CodeDom/src/PACKAGE.md b/src/libraries/System.CodeDom/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.CodeDom/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md b/src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.ComponentModel.Composition.Registration/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.Composition/src/PACKAGE.md b/src/libraries/System.ComponentModel.Composition/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.ComponentModel.Composition/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.AttributedModel/src/PACKAGE.md b/src/libraries/System.Composition.AttributedModel/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Composition.AttributedModel/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.Convention/src/PACKAGE.md b/src/libraries/System.Composition.Convention/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Composition.Convention/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.Hosting/src/PACKAGE.md b/src/libraries/System.Composition.Hosting/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Composition.Hosting/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.Runtime/src/PACKAGE.md b/src/libraries/System.Composition.Runtime/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Composition.Runtime/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition.TypedParts/src/PACKAGE.md b/src/libraries/System.Composition.TypedParts/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Composition.TypedParts/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Composition/src/PACKAGE.md b/src/libraries/System.Composition/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Composition/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md b/src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md b/src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.DirectoryServices.Protocols/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Drawing.Common/src/PACKAGE.md b/src/libraries/System.Drawing.Common/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Drawing.Common/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Formats.Cbor/src/PACKAGE.md b/src/libraries/System.Formats.Cbor/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Formats.Cbor/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Hashing/src/PACKAGE.md b/src/libraries/System.IO.Hashing/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.IO.Hashing/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Packaging/src/PACKAGE.md b/src/libraries/System.IO.Packaging/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.IO.Packaging/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.IO.Pipelines/src/PACKAGE.md b/src/libraries/System.IO.Pipelines/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.IO.Pipelines/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Management/src/PACKAGE.md b/src/libraries/System.Management/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Management/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Memory.Data/src/PACKAGE.md b/src/libraries/System.Memory.Data/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Memory.Data/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/src/PACKAGE.md b/src/libraries/System.Numerics.Tensors/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Reflection.Context/src/PACKAGE.md b/src/libraries/System.Reflection.Context/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Reflection.Context/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Resources.Extensions/src/PACKAGE.md b/src/libraries/System.Resources.Extensions/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Resources.Extensions/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md b/src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Security.Cryptography.Cose/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Security.Cryptography.ProtectedData/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md b/src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Security.Cryptography.Xml/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Security.Permissions/src/PACKAGE.md b/src/libraries/System.Security.Permissions/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Security.Permissions/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md b/src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.ServiceModel.Syndication/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md b/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Text.Encodings.Web/src/PACKAGE.md b/src/libraries/System.Text.Encodings.Web/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Text.Encodings.Web/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.AccessControl/src/PACKAGE.md b/src/libraries/System.Threading.AccessControl/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Threading.AccessControl/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.RateLimiting/src/PACKAGE.md b/src/libraries/System.Threading.RateLimiting/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Threading.RateLimiting/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md b/src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Threading/src/PACKAGE.md b/src/libraries/System.Threading/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Threading/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/System.Windows.Extensions/src/PACKAGE.md b/src/libraries/System.Windows.Extensions/src/PACKAGE.md deleted file mode 100644 index 2709a6e84e284f..00000000000000 --- a/src/libraries/System.Windows.Extensions/src/PACKAGE.md +++ /dev/null @@ -1,44 +0,0 @@ -## About - - - - - -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - -## Additional Documentation - - - -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/**LIBRARYNAME**/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/**LIBRARYNAME**) - -## Related Packages - - - -## Feedback & Contributing - - - -**LIBRARY NAME** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From 600a331c8e6e0e3ecd52290a6cc323245faa1353 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:15:20 +0200 Subject: [PATCH 248/345] Update Feedback library name markdown style --- src/libraries/System.Data.Odbc/src/PACKAGE.md | 2 +- src/libraries/System.Data.OleDb/src/PACKAGE.md | 2 +- src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md | 2 +- .../System.Diagnostics.PerformanceCounter/src/PACKAGE.md | 2 +- .../System.DirectoryServices.AccountManagement/src/PACKAGE.md | 2 +- src/libraries/System.DirectoryServices/src/PACKAGE.md | 2 +- src/libraries/System.IO.Ports/src/PACKAGE.md | 2 +- src/libraries/System.Net.Http.Json/src/PACKAGE.md | 2 +- src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md | 2 +- src/libraries/System.Speech/src/PACKAGE.md | 2 +- src/libraries/System.Threading.Channels/src/PACKAGE.md | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md index 4211f7f44ee1e5..295da33bd964c3 100644 --- a/src/libraries/System.Data.Odbc/src/PACKAGE.md +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -42,4 +42,4 @@ System.Data.OleDb is a similar package for accessing OLE DB data sources. ## Feedback & Contributing -**System.Data.Odbc** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider low-risk, high-impact fixes that are necessary to maintain or improve quality. \ No newline at end of file +System.Data.Odbc is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider low-risk, high-impact fixes that are necessary to maintain or improve quality. \ No newline at end of file diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md index 85b73459db6794..ffc6aa46332ffd 100644 --- a/src/libraries/System.Data.OleDb/src/PACKAGE.md +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -42,4 +42,4 @@ System.Data.Odbc is a similar package for accessing ODBC data sources. ## Feedback & Contributing -**System.Data.OleDb** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider low-risk, high-impact fixes that are necessary to maintain or improve quality. \ No newline at end of file +System.Data.OleDb is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports are welcome at [the GitHub repository](https://github.com/dotnet/runtime). This package is considered complete and we only consider low-risk, high-impact fixes that are necessary to maintain or improve quality. \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md index 2821a14f7c70b0..78ae5d190b780f 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md @@ -84,4 +84,4 @@ Under the [`System.Diagnostics.Eventing.Reader`](https://learn.microsoft.com/en- -**System.Diagnostics.EventLog** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.Diagnostics.EventLog is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md index 6f74c9a86379c6..22ce6c10beb7ab 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md @@ -220,4 +220,4 @@ Under the [`System.Diagnostics.PerformanceData`](https://learn.microsoft.com/en- -**System.Diagnostics.PerformanceCounter** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.Diagnostics.PerformanceCounter is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md index 1cb6350eb96903..4cb5ff5494796e 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -72,4 +72,4 @@ The main types provided by this library are: -**System.DirectoryServices.AccountManagement** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.DirectoryServices.AccountManagement is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.DirectoryServices/src/PACKAGE.md b/src/libraries/System.DirectoryServices/src/PACKAGE.md index 423ed87b7f386c..4c879dd574aa3e 100644 --- a/src/libraries/System.DirectoryServices/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices/src/PACKAGE.md @@ -79,4 +79,4 @@ The main types provided by this library are: -**System.DirectoryServices** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.DirectoryServices is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.IO.Ports/src/PACKAGE.md b/src/libraries/System.IO.Ports/src/PACKAGE.md index b450bd4318cb3e..e8494878cd28f0 100644 --- a/src/libraries/System.IO.Ports/src/PACKAGE.md +++ b/src/libraries/System.IO.Ports/src/PACKAGE.md @@ -55,4 +55,4 @@ The main type provided by this library is: -**System.IO.Ports** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.IO.Ports is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.Net.Http.Json/src/PACKAGE.md b/src/libraries/System.Net.Http.Json/src/PACKAGE.md index 5c084900142c12..23fa95df54eccf 100644 --- a/src/libraries/System.Net.Http.Json/src/PACKAGE.md +++ b/src/libraries/System.Net.Http.Json/src/PACKAGE.md @@ -47,4 +47,4 @@ The main types provided by this library are: ## Feedback & Contributing -**System.Net.Http.Json** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.Net.Http.Json is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md index ab0ba9b13aab92..44f5a5eb2ff3ee 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md @@ -45,4 +45,4 @@ The main types provided by this library are: ## Feedback & Contributing -**System.Net.Http.WinHttpHandler** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.Net.Http.WinHttpHandler is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index 4d2a8df1f1f8e4..32b4997443e164 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -98,4 +98,4 @@ The main types provided by this library are: -**System.Speech** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). +System.Speech is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). diff --git a/src/libraries/System.Threading.Channels/src/PACKAGE.md b/src/libraries/System.Threading.Channels/src/PACKAGE.md index cd9c6b829e10bb..f022aaf5ba32f2 100644 --- a/src/libraries/System.Threading.Channels/src/PACKAGE.md +++ b/src/libraries/System.Threading.Channels/src/PACKAGE.md @@ -70,4 +70,4 @@ https://www.nuget.org/packages/System.Threading.Tasks.Dataflow/ -**System.Threading.Channels** is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file +System.Threading.Channels is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file From e819ea8b534a2e94ceb4647849e1c228b04284e3 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:15:47 +0200 Subject: [PATCH 249/345] Remove en-US culture from links --- .../src/PACKAGE.md | 2 +- .../Microsoft.Bcl.Numerics/src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 4 +-- .../src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 2 +- .../Microsoft.Extensions.Http/src/PACKAGE.md | 10 +++---- src/libraries/System.Data.Odbc/src/PACKAGE.md | 2 +- .../System.Data.OleDb/src/PACKAGE.md | 2 +- .../src/PACKAGE.md | 28 +++++++++---------- .../src/PACKAGE.md | 24 ++++++++-------- .../src/PACKAGE.md | 2 +- src/libraries/System.IO.Ports/src/PACKAGE.md | 4 +-- .../src/PACKAGE.md | 4 +-- .../System.Runtime.Caching/src/PACKAGE.md | 8 +++--- src/libraries/System.Speech/src/PACKAGE.md | 8 +++--- src/libraries/System.Text.Json/src/PACKAGE.md | 4 +-- 22 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md index a4a5af4a370f6f..e0c6e8ae9adaae 100644 --- a/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.AsyncInterfaces/src/PACKAGE.md @@ -54,7 +54,7 @@ The main types provided by this library are: -* [C# Feature Specification](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/async-streams) +* [C# Feature Specification](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-8.0/async-streams) * [Walkthrough article](https://learn.microsoft.com/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8) ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md index faa3594f73e151..87db6a1678284e 100644 --- a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md @@ -40,7 +40,7 @@ The main types provided by this library are: -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.mathf) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.mathf) ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md index 8798aa1ff8f38f..a9e1c0e00615d6 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/PACKAGE.md @@ -73,7 +73,7 @@ The main types provided by this library are: * [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/caching) -* [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory) +* [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/aspnet/core/performance/caching/memory) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.caching.memory) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md index bf951fcc17968e..428cc0faf6b8e6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md @@ -62,7 +62,7 @@ The main types provided by this library are: * [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md index c7caaacac6c1c4..861b0687843ea0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/PACKAGE.md @@ -116,7 +116,7 @@ The main types provided by this library are: * [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md index 7d4c1543012d4c..91bcc9a646a501 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md @@ -31,7 +31,7 @@ The main types provided by this library are: * [Command-line configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#command-line-configuration-provider) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.commandline) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandline) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md index d9612166e7ecd4..3363278a0108c0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md @@ -53,7 +53,7 @@ The main types provided by this library are: * [Environment variable configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.environmentvariables) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.environmentvariables) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md index a86dbd4757ea19..1a32dfbb88ab79 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md @@ -31,7 +31,7 @@ The main types provided by this library are: * [INI configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#ini-configuration-provider) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.ini) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.ini) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md index b1b0a8fff8421c..777a3420ad3319 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md @@ -86,8 +86,8 @@ The main types provided by this library are: -* [JSON configuration provider](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#json-configuration-provider) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.json) +* [JSON configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#json-configuration-provider) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.json) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md index 976bf5598f60f4..12ec8f399a9120 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md @@ -32,7 +32,7 @@ The main types provided by this library are: * [Configuration in .NET](https://learn.microsoft.com/dotnet/core/extensions/configuration) * [Safe storage of app secrets in development in ASP.NET Core](https://learn.microsoft.com/aspnet/core/security/app-secrets) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.usersecrets) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.usersecrets) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md index 602c919514ddce..38560635038cb8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md @@ -86,7 +86,7 @@ The main types provided by this library are: * [XML configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#xml-configuration-provider) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.xml) +* [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.xml) ## Related Packages diff --git a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md index 15fc9683b87abd..294cb308cc7a9b 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Http/src/PACKAGE.md @@ -16,7 +16,7 @@ -Note that lifetime management of `HttpClient` instances created by `HttpClientFactory` is completely different from instances created manually. The strategies are to use either short-lived clients created by `HttpClientFactory` or long-lived clients with `PooledConnectionLifetime` set up. For more information, see the [HttpClient lifetime management section](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#httpclient-lifetime-management) in the conceptual docs and [Guidelines for using HTTP clients](https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines). +Note that lifetime management of `HttpClient` instances created by `HttpClientFactory` is completely different from instances created manually. The strategies are to use either short-lived clients created by `HttpClientFactory` or long-lived clients with `PooledConnectionLifetime` set up. For more information, see the [HttpClient lifetime management section](https://learn.microsoft.com/dotnet/core/extensions/httpclient-factory#httpclient-lifetime-management) in the conceptual docs and [Guidelines for using HTTP clients](https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines). ### Configuring HttpClient @@ -61,10 +61,10 @@ The main types provided by this library are: -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory) - * Also see [HttpClient guidelines](https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines) conceptual doc -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.net.http?view=dotnet-plat-ext-7.0) - * Also see [`AddHttpClient` extension method](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.httpclientfactoryservicecollectionextensions?view=dotnet-plat-ext-7.0) API doc +* [Conceptual documentation](https://learn.microsoft.com/dotnet/core/extensions/httpclient-factory) + * Also see [HttpClient guidelines](https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines) conceptual doc +* [API documentation](https://learn.microsoft.com/dotnet/api/system.net.http?view=dotnet-plat-ext-7.0) + * Also see [`AddHttpClient` extension method](https://learn.microsoft.com/dotnet/api/microsoft.extensions.dependencyinjection.httpclientfactoryservicecollectionextensions?view=dotnet-plat-ext-7.0) API doc ## Related Packages diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md index 295da33bd964c3..7195ca77a50064 100644 --- a/src/libraries/System.Data.Odbc/src/PACKAGE.md +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -34,7 +34,7 @@ while (reader.Read()) ## Additional Documentation -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.data.odbc) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.data.odbc) ## Related Packages diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md index ffc6aa46332ffd..be973625ebef7d 100644 --- a/src/libraries/System.Data.OleDb/src/PACKAGE.md +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -34,7 +34,7 @@ while (reader.Read()) ## Additional Documentation -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.data.oledb) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.data.oledb) ## Related Packages diff --git a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md index 78ae5d190b780f..56e111a68ac802 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.EventLog/src/PACKAGE.md @@ -50,28 +50,28 @@ Notes: The main types provided by this library are: -Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace, the main types are: +Under the [`System.Diagnostics`](https://learn.microsoft.com/dotnet/api/System.Diagnostics) namespace, the main types are: -- [`System.Diagnostics.EventLog`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLog) -- [`System.Diagnostics.EventLogEntry`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntry) -- [`System.Diagnostics.EventLogEntryCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntryCollection) -- [`System.Diagnostics.EventLogEntryType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLogEntryType) +- [`System.Diagnostics.EventLog`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.EventLog) +- [`System.Diagnostics.EventLogEntry`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.EventLogEntry) +- [`System.Diagnostics.EventLogEntryCollection`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.EventLogEntryCollection) +- [`System.Diagnostics.EventLogEntryType`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.EventLogEntryType) -Under the [`System.Diagnostics.Eventing.Reader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader) namespace, the main types are: +Under the [`System.Diagnostics.Eventing.Reader`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader) namespace, the main types are: -- [`System.Diagnostics.Eventing.Reader.EventLogQuery`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogQuery) -- [`System.Diagnostics.Eventing.Reader.EventLogReader`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogReader) -- [`System.Diagnostics.Eventing.Reader.EventLogRecord`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogRecord) -- [`System.Diagnostics.Eventing.Reader.EventLogSession`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogSession) -- [`System.Diagnostics.Eventing.Reader.EventLogType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogType) -- [`System.Diagnostics.Eventing.Reader.EventRecord`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.Eventing.Reader.EventRecord) +- [`System.Diagnostics.Eventing.Reader.EventLogQuery`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogQuery) +- [`System.Diagnostics.Eventing.Reader.EventLogReader`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogReader) +- [`System.Diagnostics.Eventing.Reader.EventLogRecord`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogRecord) +- [`System.Diagnostics.Eventing.Reader.EventLogSession`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogSession) +- [`System.Diagnostics.Eventing.Reader.EventLogType`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader.EventLogType) +- [`System.Diagnostics.Eventing.Reader.EventRecord`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.Eventing.Reader.EventRecord) ## Additional Documentation -- [Microsoft Learn - System.Diagnostics.EventLog API reference](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.EventLog) -- [Windows App Development - Event logging](https://learn.microsoft.com/en-us/windows/win32/eventlog/event-logging) +- [Microsoft Learn - System.Diagnostics.EventLog API reference](https://learn.microsoft.com/dotnet/api/System.Diagnostics.EventLog) +- [Windows App Development - Event logging](https://learn.microsoft.com/windows/win32/eventlog/event-logging) - [GitHub - Source code](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Diagnostics.EventLog) ## Related Packages diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md index 22ce6c10beb7ab..475291274ff289 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/PACKAGE.md @@ -188,26 +188,26 @@ Notes: The main types provided by this library are: -Under the [`System.Diagnostics`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics) namespace, the main types are: +Under the [`System.Diagnostics`](https://learn.microsoft.com/dotnet/api/System.Diagnostics) namespace, the main types are: -* [`System.Diagnostics.CounterCreationData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterCreationData) -* [`System.Diagnostics.CounterCreationDataCollection`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.CounterCreationDataCollection) -* [`System.Diagnostics.PerformanceCounter`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceCounter) +* [`System.Diagnostics.CounterCreationData`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.CounterCreationData) +* [`System.Diagnostics.CounterCreationDataCollection`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.CounterCreationDataCollection) +* [`System.Diagnostics.PerformanceCounter`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.PerformanceCounter) -Under the [`System.Diagnostics.PerformanceData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData) namespace, the main types are: +Under the [`System.Diagnostics.PerformanceData`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.PerformanceData) namespace, the main types are: -* [`System.Diagnostics.PerformanceData.CounterData`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterData) -* [`System.Diagnostics.PerformanceData.CounterSet`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterSet) -* [`System.Diagnostics.PerformanceData.CounterType`](https://learn.microsoft.com/en-us/dotnet/api/System.Diagnostics.PerformanceData.CounterType) +* [`System.Diagnostics.PerformanceData.CounterData`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.PerformanceData.CounterData) +* [`System.Diagnostics.PerformanceData.CounterSet`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.PerformanceData.CounterSet) +* [`System.Diagnostics.PerformanceData.CounterType`](https://learn.microsoft.com/dotnet/api/System.Diagnostics.PerformanceData.CounterType) ## Additional Documentation -* [Microsoft Learn - System.Diagnostics.PerformanceCounter API reference](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.performancecounter?view=dotnet-plat-ext-7.0) -* [Windows App Development - Performance Counters](https://learn.microsoft.com/en-us/windows/win32/perfctrs/performance-counters-portal) -* [Windows Performance and Reliability - Windows Performance Monitor](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc749249(v=ws.11)) -* [Windows Server - perfmon](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/perfmon) +* [Microsoft Learn - System.Diagnostics.PerformanceCounter API reference](https://learn.microsoft.com/dotnet/api/system.diagnostics.performancecounter?view=dotnet-plat-ext-7.0) +* [Windows App Development - Performance Counters](https://learn.microsoft.com/windows/win32/perfctrs/performance-counters-portal) +* [Windows Performance and Reliability - Windows Performance Monitor](https://learn.microsoft.com/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc749249(v=ws.11)) +* [Windows Server - perfmon](https://learn.microsoft.com/windows-server/administration/windows-commands/perfmon) * [GitHub - Source code](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Diagnostics.PerformanceCounter) ## Related Packages diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md index 4cb5ff5494796e..7d761e089fbb8c 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -57,7 +57,7 @@ The main types provided by this library are: * Conceptual documentations: - - [System.DirectoryServices.AccountManagement Namespace Overview](https://learn.microsoft.com/en-us/previous-versions/bb384379(v=vs.90)) + - [System.DirectoryServices.AccountManagement Namespace Overview](https://learn.microsoft.com/previous-versions/bb384379(v=vs.90)) - [About System.DirectoryServices.AccountManagement](https://learn.microsoft.com//previous-versions/bb384375(v=vs.90)) - [Using System.DirectoryServices.AccountManagement](https://learn.microsoft.com/previous-versions/bb384384(v=vs.90)) * API documentation diff --git a/src/libraries/System.IO.Ports/src/PACKAGE.md b/src/libraries/System.IO.Ports/src/PACKAGE.md index e8494878cd28f0..90da18ddefd2f0 100644 --- a/src/libraries/System.IO.Ports/src/PACKAGE.md +++ b/src/libraries/System.IO.Ports/src/PACKAGE.md @@ -43,8 +43,8 @@ The main type provided by this library is: -* [SerialPort class documentation](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport?view=dotnet-plat-ext-7.0) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/System.IO.Ports) +* [SerialPort class documentation](https://learn.microsoft.com/dotnet/api/system.io.ports.serialport?view=dotnet-plat-ext-7.0) +* [API documentation](https://learn.microsoft.com/dotnet/api/System.IO.Ports) ## Related Packages diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md index 44f5a5eb2ff3ee..dcc800e598728a 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/PACKAGE.md @@ -1,6 +1,6 @@ ## About -This package provides an [`HttpMessageHandler`](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpmessagehandler) implementation backed by [Windows HTTP Services (WinHTTP)](https://learn.microsoft.com/en-us/windows/win32/winhttp/winhttp-start-page). +This package provides an [`HttpMessageHandler`](https://learn.microsoft.com/dotnet/api/system.net.http.httpmessagehandler) implementation backed by [Windows HTTP Services (WinHTTP)](https://learn.microsoft.com/windows/win32/winhttp/winhttp-start-page). While the use of the default `HttpClientHandler` is highly recommended for applications targeting modern .NET, `WinHttpHandler` might help migration scenarios by providing an alternative HTTP backend for Windows that works consistently accross .NET Framework and modern .NET. ## Key Features @@ -41,7 +41,7 @@ The main types provided by this library are: ## Additional Documentation -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.winhttphandler) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.net.http.winhttphandler) ## Feedback & Contributing diff --git a/src/libraries/System.Runtime.Caching/src/PACKAGE.md b/src/libraries/System.Runtime.Caching/src/PACKAGE.md index 56b8069b131681..9f9b02700d5ba2 100644 --- a/src/libraries/System.Runtime.Caching/src/PACKAGE.md +++ b/src/libraries/System.Runtime.Caching/src/PACKAGE.md @@ -4,7 +4,7 @@ Packaged set of simple caching API's derived from those of the same namespace available in .NET Framework since 4.0. This package is intended for use as a bridge when porting .NET Framework applications to .NET. -[Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/[IMemoryCache](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-7.0) is recommended over `System.Runtime.Caching`/`MemoryCache` because it's better integrated into ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0). +[Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/[IMemoryCache](https://learn.microsoft.com/aspnet/core/performance/caching/memory?view=aspnetcore-7.0) is recommended over `System.Runtime.Caching`/`MemoryCache` because it's better integrated into ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](https://learn.microsoft.com/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0). > > [!IMPORTANT] > Use `System.Runtime.Caching`/`MemoryCache` as a compatibility bridge when porting code from .NET 4.x to .NET Core. @@ -34,10 +34,10 @@ The main types provided by this library are: -[MemoryCache.PhysicalMemoryLimit](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.caching.memorycache.physicalmemorylimit?view=dotnet-plat-ext-7.0) property is only supported on windows. +[MemoryCache.PhysicalMemoryLimit](https://learn.microsoft.com/dotnet/api/system.runtime.caching.memorycache.physicalmemorylimit?view=dotnet-plat-ext-7.0) property is only supported on windows. -* [Caching in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/caching) -* [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-7.0 ) +* [Caching in .NET](https://learn.microsoft.com/dotnet/core/extensions/caching) +* [Cache in-memory in ASP.NET Core](https://learn.microsoft.com/aspnet/core/performance/caching/memory?view=aspnetcore-7.0 ) ## Related Packages diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index 32b4997443e164..e7d46cc047307e 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -1,7 +1,7 @@ ## About -Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other platforms. +Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other platforms. This package is provided primarily for compatibility with code being ported from .NET Framework and is not accepting new features. @@ -90,9 +90,9 @@ The main types provided by this library are: -* [Conceptual documentation](https://learn.microsoft.com/en-us/previous-versions/office/developer/speech-technologies/hh361625(v%3doffice.14)) -* [Speech.Recognition API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.speech.recognition) -* [Speech.Synthesis API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.speech.synthesis) +* [Conceptual documentation](https://learn.microsoft.com/previous-versions/office/developer/speech-technologies/hh361625(v%3doffice.14)) +* [Speech.Recognition API documentation](https://learn.microsoft.com/dotnet/api/system.speech.recognition) +* [Speech.Synthesis API documentation](https://learn.microsoft.com/dotnet/api/system.speech.synthesis) ## Feedback & Contributing diff --git a/src/libraries/System.Text.Json/src/PACKAGE.md b/src/libraries/System.Text.Json/src/PACKAGE.md index 7cbbec76e65b32..1ddd210a0acb28 100644 --- a/src/libraries/System.Text.Json/src/PACKAGE.md +++ b/src/libraries/System.Text.Json/src/PACKAGE.md @@ -239,8 +239,8 @@ The main types provided by this library are: ## Additional Documentation -* [Conceptual documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/overview) -* [API documentation](https://learn.microsoft.com/en-us/dotnet/api/system.text.json) +* [Conceptual documentation](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/overview) +* [API documentation](https://learn.microsoft.com/dotnet/api/system.text.json) ## Related Packages From 8890301670c4e933b98b17a18ddf254303d580e0 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:17:31 +0200 Subject: [PATCH 250/345] Replace important markdown tag with bold --- src/libraries/System.Runtime.Caching/src/PACKAGE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.Caching/src/PACKAGE.md b/src/libraries/System.Runtime.Caching/src/PACKAGE.md index 9f9b02700d5ba2..60abdb27032f1d 100644 --- a/src/libraries/System.Runtime.Caching/src/PACKAGE.md +++ b/src/libraries/System.Runtime.Caching/src/PACKAGE.md @@ -6,9 +6,7 @@ Packaged set of simple caching API's derived from those of the same namespace av [Microsoft.Extensions.Caching.Memory](https://www.nuget.org/packages/Microsoft.Extensions.Caching.Memory/)/[IMemoryCache](https://learn.microsoft.com/aspnet/core/performance/caching/memory?view=aspnetcore-7.0) is recommended over `System.Runtime.Caching`/`MemoryCache` because it's better integrated into ASP.NET Core. For example, `IMemoryCache` works natively with ASP.NET Core [dependency injection](https://learn.microsoft.com/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-7.0). -> > [!IMPORTANT] -> Use `System.Runtime.Caching`/`MemoryCache` as a compatibility bridge when porting code from .NET 4.x to .NET Core. - +**Use `System.Runtime.Caching`/`MemoryCache` as a compatibility bridge when porting code from .NET 4.x to .NET Core.** ## Key Features From 0b106c54af8d9d8a7dbf55d3d790f17d2045f327 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:19:24 +0200 Subject: [PATCH 251/345] MathF PR feedback --- src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md index 87db6a1678284e..620514e8bb0b82 100644 --- a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md @@ -13,17 +13,12 @@ As of .NET Core 2.0 and .NET Standard 2.1, the C# language has support for math ```C# using System; -using System.MathF. internal static class Program { private static async Task Main() - { - Console.WriteLine("Starting..."); - + { Console.WriteLine(MathF.Max(1f, 5f)); // returns 5f - - Console.WriteLine("Finished!"); } } ``` From 2cf3fafb650f789a3d9432803b6d1a5916c3decc Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:52:31 +0200 Subject: [PATCH 252/345] Add System.Management packag readme --- .../System.Management/src/PACKAGE.md | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/libraries/System.Management/src/PACKAGE.md diff --git a/src/libraries/System.Management/src/PACKAGE.md b/src/libraries/System.Management/src/PACKAGE.md new file mode 100644 index 00000000000000..733cc750bcac1f --- /dev/null +++ b/src/libraries/System.Management/src/PACKAGE.md @@ -0,0 +1,69 @@ +## About + + +Provides access to a rich set of management information and management events about the system, devices, and applications instrumented to the Windows Management Instrumentation (WMI) infrastructure. Not supported on other platforms. + +## Key Features + + + +* Consume Windows Management Instrumentation (WMI) data and events +* High performance extensible event mechanism + +## How to Use + + + +### Retrieve management information +```C# +using System.Management; + +// Get the WMI class +ManagementClass managementClass = new("Win32_Processor"); + +// Loop through the WMI class instances and print the processor information found +foreach (ManagementObject managementObject in managementClass.GetInstances()) +{ + Console.WriteLine("--- Processor information ---"); + Console.WriteLine($"Name: {managementObject["Name"]}"); + Console.WriteLine($"Architecture: {managementObject["Architecture"]}"); +} +``` + +### Query management information via the SelectQuery type +```C# +using System.Management; + +// Search for win32 services with a stopped state +SelectQuery selectQuery = new("Win32_Service", "State = 'Stopped'"); +ManagementObjectSearcher managementObjectSearcher = new(selectQuery); + +foreach (ManagementObject service in managementObjectSearcher.Get()) +{ + Console.WriteLine(service.ToString()); +} +``` + +## Main Types + + + +The main types provided by this library are: + +* `System.Management.ManagementClass` +* `System.Management.ManagementObject` +* `System.Management.SelectQuery` + +## Additional Documentation + + + +* [Conceptual documentation](https://learn.microsoft.com/windows/win32/wmisdk/wmi-start-page) +* [System.Management API documentation](https://learn.microsoft.com/dotnet/api/system.management?view=dotnet-plat-ext-7.0) +* [System.Management.ManagementClass documentation](https://learn.microsoft.com/dotnet/api/system.management.managementclass.-ctor?view=dotnet-plat-ext-7.0) + +## Feedback & Contributing + + + +System.Management is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From dc9c01278e2bd990c97588fabe8e4beffd757d10 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 14:57:53 +0200 Subject: [PATCH 253/345] Fix trailing whitespace --- src/libraries/System.Management/src/PACKAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Management/src/PACKAGE.md b/src/libraries/System.Management/src/PACKAGE.md index 733cc750bcac1f..280347191d1013 100644 --- a/src/libraries/System.Management/src/PACKAGE.md +++ b/src/libraries/System.Management/src/PACKAGE.md @@ -30,7 +30,7 @@ foreach (ManagementObject managementObject in managementClass.GetInstances()) } ``` -### Query management information via the SelectQuery type +### Query management information via the SelectQuery type ```C# using System.Management; From c59bf659eec0447129f70416c0a9659acc7aead5 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 15:30:08 +0200 Subject: [PATCH 254/345] Add ServiceController package readme --- .../src/PACKAGE.md | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md b/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md new file mode 100644 index 00000000000000..902a69d0ae2858 --- /dev/null +++ b/src/libraries/System.ServiceProcess.ServiceController/src/PACKAGE.md @@ -0,0 +1,69 @@ +## About + + +Provides the System.ServiceProcess.ServiceController API, which allows to connect to a Windows service, manipulate it, or get information about it. Not supported on other platforms. + +## Key Features + + + +* Retrieve information from Windows services +* Connect to and manipulate Windows services (start, pause, stop or other operations) + +## How to Use + + + +### Retrieve Windows service information +```C# +using System.ServiceProcess; + +// Loop through all installed Windows services and print the name, status and display name. +foreach (ServiceController serviceController in ServiceController.GetServices()) +{ + Console.WriteLine("Name: " + serviceController.ServiceName); + Console.WriteLine("Status: " + serviceController.Status.ToString()); + Console.WriteLine("Display name: " + serviceController.DisplayName); +} + +// Loop through all installed device driver services +foreach (ServiceController serviceController in ServiceController.GetDevices()) +{ + Console.WriteLine("Name: " + serviceController.ServiceName); + Console.WriteLine("Status: " + serviceController.Status.ToString()); + Console.WriteLine("Display name: " + serviceController.DisplayName); +} +``` + +### Manipulate a Windows service +```C# +using System.ServiceProcess; + +ServiceController service = new("TestServiceName"); +if (service.CanStop && service.Status != ServiceControllerStatus.Stopped && service.Status != ServiceControllerStatus.StopPending) +{ + service.Stop(); +} +``` + +## Main Types + + + +The main types provided by this library are: + +* `System.ServiceProcess.ServiceController` +* `System.ServiceProcess.ServiceControllerStatus` +* `System.ServiceProcess.ServiceType` + +## Additional Documentation + + + +* [System.ServiceController API documentation](https://learn.microsoft.com/dotnet/api/system.serviceprocess.servicecontroller?view=dotnet-plat-ext-7.0) + +## Feedback & Contributing + + + +System.ServiceProcess.ServiceController is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). From 21727cee290d157c93e4ebd2b292b0021b452f8b Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 15:51:32 +0200 Subject: [PATCH 255/345] Clean-up --- .../Microsoft.Bcl.TimeProvider/src/PACKAGE.md | 1 - .../src/PACKAGE.md | 2 - .../src/PACKAGE.md | 26 ----------- .../src/PACKAGE.md | 22 ---------- .../src/PACKAGE.md | 26 ----------- .../src/PACKAGE.md | 26 ----------- .../src/PACKAGE.md | 22 ---------- .../src/PACKAGE.md | 26 ----------- .../src/PACKAGE.md | 22 ---------- .../src/PACKAGE.md | 22 ---------- .../src/PACKAGE.md | 21 ++++++++- .../src/PACKAGE.md | 1 - .../src/PACKAGE.md | 44 ++++++++++++++++--- .../src/PACKAGE.md | 13 +----- .../System.Reflection.Metadata/src/PACKAGE.md | 8 ---- .../src/PACKAGE.md | 17 +------ .../System.Runtime.Caching/src/PACKAGE.md | 10 ++--- 17 files changed, 64 insertions(+), 245 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md index bf767f3354d39a..f3c9c372cf2caf 100644 --- a/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.TimeProvider/src/PACKAGE.md @@ -52,7 +52,6 @@ The main types provided by this library are: * [API documentation](https://learn.microsoft.com/dotnet/api/system.timeprovider) - ## Feedback & Contributing Microsoft.Bcl.TimeProvider is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md index 428cc0faf6b8e6..e744e1b9e73df1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/PACKAGE.md @@ -4,7 +4,6 @@ Provides abstractions of key-value pair based configuration. Interfaces defined in this package are implemented by classes in [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and other configuration packages. - ## Key Features @@ -44,7 +43,6 @@ var options = config.Get(); Console.WriteLine(options.NamedProperty); // returns "value for named property" ``` - ## Main Types diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md index 91bcc9a646a501..8b1734c0421fb3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md @@ -4,28 +4,6 @@ Command line configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from the command line arguments of your application. You can use [CommandLineConfigurationExtensions.AddCommandLine](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandlineconfigurationextensions.addcommandline) extension method on `IConfigurationBuilder` to add the command line configuration provider to the configuration builder. -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -33,10 +11,6 @@ The main types provided by this library are: * [Command-line configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#command-line-configuration-provider) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandline) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md index 3363278a0108c0..eb9a67bfbfda25 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/PACKAGE.md @@ -4,14 +4,6 @@ Environment variables configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from environment variables. You can use [EnvironmentVariablesExtensions.AddEnvironmentVariables](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.environmentvariablesextensions.addenvironmentvariables) extension method on `IConfigurationBuilder` to add the environment variables configuration provider to the configuration builder. -## Key Features - - - -* -* -* - ## How to Use @@ -38,16 +30,6 @@ class Program } ``` -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -55,10 +37,6 @@ The main types provided by this library are: * [Environment variable configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.environmentvariables) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md index 60b2096828e8ec..4a4f404102c89a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/PACKAGE.md @@ -4,28 +4,6 @@ Provides a base class for file-based configuration providers used with [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/) and extension methods for configuring them. -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -34,10 +12,6 @@ The main types provided by this library are: * [Microsoft.Extensions.Configuration.FileConfigurationProvider](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.fileconfigurationprovider) * [Microsoft.Extensions.Configuration.FileConfigurationExtensions](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.fileconfigurationextensions) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md index 1a32dfbb88ab79..0fc660489a4fc6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md @@ -4,28 +4,6 @@ INI configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from [INI files](https://en.wikipedia.org/wiki/INI_file). You can use [IniConfigurationExtensions.AddIniFile](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iniconfigurationextensions.addinifile) extension method on `IConfigurationBuilder` to add INI configuration provider to the configuration builder. -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -33,10 +11,6 @@ The main types provided by this library are: * [INI configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#ini-configuration-provider) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.ini) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md index 777a3420ad3319..825b3dbe412d4d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/PACKAGE.md @@ -4,14 +4,6 @@ JSON configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read your application's settings from a JSON file. You can use [JsonConfigurationExtensions.AddJsonFile](https://docs.microsoft.com/dotnet/api/microsoft.extensions.configuration.jsonconfigurationextensions.addjsonfile) extension method on `IConfigurationBuilder` to add the JSON configuration provider to the configuration builder. -## Key Features - - - -* -* -* - ## How to Use @@ -72,16 +64,6 @@ You can include a configuration file using a code like this in your `.csproj` fi ``` -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -89,10 +71,6 @@ The main types provided by this library are: * [JSON configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#json-configuration-provider) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.json) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md index 12ec8f399a9120..1fe9ee6c98939e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/PACKAGE.md @@ -4,28 +4,6 @@ User secrets configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). User secrets mechanism enables you to override application configuration settings with values stored in the local secrets file. You can use [UserSecretsConfigurationExtensions.AddUserSecrets](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.usersecretsconfigurationextensions.addusersecrets) extension method on `IConfigurationBuilder` to add user secrets provider to the configuration builder. -## Key Features - - - -* -* -* - -## How to Use - - - -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -34,10 +12,6 @@ The main types provided by this library are: * [Safe storage of app secrets in development in ASP.NET Core](https://learn.microsoft.com/aspnet/core/security/app-secrets) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.usersecrets) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md index 38560635038cb8..209645bc5a4732 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/PACKAGE.md @@ -4,14 +4,6 @@ XML configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from XML files. You can use [XmlConfigurationExtensions.AddXmlFile](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.xmlconfigurationextensions.addxmlfile) extension method on `IConfigurationBuilder` to add XML configuration provider to the configuration builder. -## Key Features - - - -* -* -* - ## How to Use @@ -71,16 +63,6 @@ You can include a configuration file using a code like this in your `.csproj` fi ``` -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -88,10 +70,6 @@ The main types provided by this library are: * [XML configuration provider](https://learn.microsoft.com/dotnet/core/extensions/configuration-providers#xml-configuration-provider) * [API documentation](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.xml) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md index d8bcd473f60d0a..19b13040a8aea9 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/PACKAGE.md @@ -6,14 +6,6 @@ Provides abstractions for reading `.deps` files. When a .NET application is comp By default, the dependency manifest contains information about the application's target framework and runtime dependencies. Set the [PreserveCompilationContext](https://docs.microsoft.com/dotnet/core/project-sdk/msbuild-props#preservecompilationcontext) project property to `true` to additionally include information about reference assemblies used during compilation. -## Key Features - - - -* -* -* - ## How to Use @@ -42,16 +34,6 @@ class Program } ``` -## Main Types - - - -The main types provided by this library are: - -* `` -* `` -* `` - ## Additional Documentation @@ -60,10 +42,6 @@ The main types provided by this library are: * [Microsoft.Extensions.DependencyModel namespace](https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencymodel) * [Microsoft.Extensions.DependencyModel.DependencyContext](https://docs.microsoft.com/dotnet/api/microsoft.extensions.dependencymodel.dependencycontext) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md index a9cd4f5727700b..836433b1a4bba5 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Hosting/src/PACKAGE.md @@ -1,12 +1,21 @@ ## About + + + Contains the .NET Generic Host `HostBuilder` which layers on the `Microsoft.Extensions.Hosting.Abstractions` package. ## Key Features + + + * Contains the .NET Generic Host `HostBuilder`. ## How to Use + + + For a console app project: -```cs +```C# using (IHost host = new HostBuilder().Build()) { var lifetime = host.Services.GetRequiredService(); @@ -34,7 +43,11 @@ For a console app project: ``` ## Main Types + + + The main types provided by this library are: + * `Microsoft.Extensions.Host`. * `Microsoft.Extensions.Hosting.HostApplicationBuilder` * `Microsoft.Extensions.Hosting.HostBuilder` @@ -42,6 +55,9 @@ The main types provided by this library are: * `Microsoft.Extensions.Hosting.IHostedLifecycleService` ## Additional Documentation + + + * [Generic host](https://learn.microsoft.com/dotnet/core/extensions/generic-host) * API documentation - [Host](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.host) @@ -49,6 +65,9 @@ The main types provided by this library are: - [HostBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.hosting.hostbuilder) ## Related Packages + + + - `Microsoft.Extensions.Configuration` - `Microsoft.Extensions.DependencyInjection` - `Microsoft.Extensions.Hosting.Abstractions` diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md index b35f529af9c06c..69823b6d4d3faa 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/PACKAGE.md @@ -10,7 +10,6 @@ * Allow logging to the console using the [Microsoft.Extensions.Logging](https://www.nuget.org/packages/Microsoft.Extensions.Logging/) package. * Provide extension methods for the [ILoggingBuilder](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggingbuilder) and [ILoggerProviderConfiguration](https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.configuration.iloggerproviderconfiguration-1) classes. - ## How to Use diff --git a/src/libraries/System.Collections.Immutable/src/PACKAGE.md b/src/libraries/System.Collections.Immutable/src/PACKAGE.md index 1b39d42bb175f0..563660c9be59ea 100644 --- a/src/libraries/System.Collections.Immutable/src/PACKAGE.md +++ b/src/libraries/System.Collections.Immutable/src/PACKAGE.md @@ -18,15 +18,49 @@ The `System.Collections.Immutable` library is built-in as part of the shared fra +```C# +using System.Collections.Immutable; + +// Create immutable set of strings +ImmutableHashSet colors = ImmutableHashSet.Create("Red", "Green", "Blue"); + +// Create a new set by adding and removing items from the original set +ImmutableHashSet colorsModified = colors.Remove("Red").Add("Orange"); + +foreach (string s in colorsModified) +{ + Console.WriteLine(s); +} + +/* Example output: + Blue + Green + Orange + */ + ``` + ## Main Types The main types provided by this library are: -* `` -* `` -* `` +* `System.Collections.Immutable.ImmutableArray` +* `System.Collections.Immutable.ImmutableArray` +* `System.Collections.Immutable.ImmutableDictionary` +* `System.Collections.Immutable.ImmutableDictionary` +* `System.Collections.Immutable.ImmutableHashSet` +* `System.Collections.Immutable.ImmutableHashSet` +* `System.Collections.Immutable.ImmutableList` +* `System.Collections.Immutable.ImmutableList` +* `System.Collections.Immutable.ImmutableQueue` +* `System.Collections.Immutable.ImmutableQueue` +* `System.Collections.Immutable.ImmutableSortedDictionary` +* `System.Collections.Immutable.ImmutableSortedDictionary` +* `System.Collections.Immutable.ImmutableSortedSet` +* `System.Collections.Immutable.ImmutableSortedSet` +* `System.Collections.Immutable.ImmutableStack` +* `System.Collections.Immutable.ImmutableStack` ## Additional Documentation @@ -35,10 +69,6 @@ The main types provided by this library are: - [Collections and Data Structures](https://docs.microsoft.com/dotnet/standard/collections/) - [API documentation](https://docs.microsoft.com/dotnet/api/system.collections.immutable) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md b/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md index fdaea06fddb7e3..3a315884484cae 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md +++ b/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md @@ -4,14 +4,6 @@ Provides types that support using XML configuration files (`app.config`). This package exists only to support migrating existing .NET Framework code that already uses System.Configuration. When writing new code, use another configuration system instead, such as [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). -## Key Features - - - -* -* -* - ## How to Use @@ -75,9 +67,8 @@ To run this example, include an `app.config` file with the following content in The main types provided by this library are: -* `` -* `` -* `` +* `System.Configuration.Configuration` +* `System.Configuration.ConfigurationManager` ## Additional Documentation diff --git a/src/libraries/System.Reflection.Metadata/src/PACKAGE.md b/src/libraries/System.Reflection.Metadata/src/PACKAGE.md index 42ee1764292807..df290dd1ab0f50 100644 --- a/src/libraries/System.Reflection.Metadata/src/PACKAGE.md +++ b/src/libraries/System.Reflection.Metadata/src/PACKAGE.md @@ -6,14 +6,6 @@ This package provides a low-level .NET (ECMA-335) metadata reader and writer. It The `System.Reflection.Metadata` library is included in the .NET Runtime shared framework. The package can be installed when you need to use it in other target frameworks. -## Key Features - - - -* -* -* - ## How to Use diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md b/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md index 1f0e974b2bab60..f16805d7d3f14a 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/PACKAGE.md @@ -4,14 +4,6 @@ Provides read-only reflection on assemblies in an isolated context with support for assemblies that target different processor architectures and runtimes. Using MetadataLoadContext enables you to inspect assemblies without loading them into the main execution context. Assemblies in MetadataLoadContext are treated only as metadata, that is, you can read information about their members, but cannot execute any code contained in them. -## Key Features - - - -* -* -* - ## How to Use @@ -51,9 +43,8 @@ class Program The main types provided by this library are: -* `` -* `` -* `` +* `System.Reflection.MetadataLoadContext` +* `System.Reflection.MetadataAssemblyResolver` ## Additional Documentation @@ -63,10 +54,6 @@ The main types provided by this library are: * [System.Reflection.MetadataLoadContext](https://docs.microsoft.com/dotnet/api/system.reflection.metadataloadcontext) * [System.Reflection.MetadataAssemblyResolver](https://docs.microsoft.com/dotnet/api/system.reflection.metadataassemblyresolver) -## Related Packages - - - ## Feedback & Contributing diff --git a/src/libraries/System.Runtime.Caching/src/PACKAGE.md b/src/libraries/System.Runtime.Caching/src/PACKAGE.md index 60abdb27032f1d..5b79f3f7cfb01c 100644 --- a/src/libraries/System.Runtime.Caching/src/PACKAGE.md +++ b/src/libraries/System.Runtime.Caching/src/PACKAGE.md @@ -12,13 +12,9 @@ Packaged set of simple caching API's derived from those of the same namespace av -* -* -* - -## How to Use - - +* Use caching facilities like in ASP.NET, but without a dependency on the System.Web assembly. +* Extensible caching mechanism +* Possible to create custom caching providers ## Main Types From ed430fc763f79735a859d292bd9af64b0650257b Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 15:57:55 +0200 Subject: [PATCH 256/345] More clean-up --- .../Microsoft.Bcl.Numerics/src/PACKAGE.md | 3 +- .../src/PACKAGE.md | 26 +++++++++++ .../src/PACKAGE.md | 45 +++++++++++++++++++ .../src/PACKAGE.md | 1 + .../src/PACKAGE.md | 8 ---- .../System.Reflection.Metadata/src/PACKAGE.md | 12 +++-- 6 files changed, 79 insertions(+), 16 deletions(-) diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md index 620514e8bb0b82..5ce176a315dedb 100644 --- a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md @@ -8,9 +8,10 @@ As of .NET Core 2.0 and .NET Standard 2.1, the C# language has support for math * Enables the use of MathF on older .NET platforms - ## How to Use + + ```C# using System; diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md index 8b1734c0421fb3..3714573d5d449b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/PACKAGE.md @@ -4,6 +4,32 @@ Command line configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from the command line arguments of your application. You can use [CommandLineConfigurationExtensions.AddCommandLine](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.commandlineconfigurationextensions.addcommandline) extension method on `IConfigurationBuilder` to add the command line configuration provider to the configuration builder. +## How to Use + + + +The following example shows how to read application configuration from the command line. You can use a command like `dotnet run --InputPath "c:\fizz" --OutputPath "c:\buzz"` to run it. + +```C# +using System; +using Microsoft.Extensions.Configuration; + +class Program +{ + static void Main(string[] args) + { + // Build a configuration object from command line + IConfiguration config = new ConfigurationBuilder() + .AddCommandLine(args) + .Build(); + + // Read configuration values + Console.WriteLine($"InputPath: {config["InputPath"]}"); + Console.WriteLine($"OutputPath: {config["OutputPath"]}"); + } +} +``` + ## Additional Documentation diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md index 0fc660489a4fc6..a987b88924d64d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/PACKAGE.md @@ -4,6 +4,51 @@ INI configuration provider implementation for [Microsoft.Extensions.Configuration](https://www.nuget.org/packages/Microsoft.Extensions.Configuration/). This package enables you to read configuration parameters from [INI files](https://en.wikipedia.org/wiki/INI_file). You can use [IniConfigurationExtensions.AddIniFile](https://learn.microsoft.com/dotnet/api/microsoft.extensions.configuration.iniconfigurationextensions.addinifile) extension method on `IConfigurationBuilder` to add INI configuration provider to the configuration builder. +## How to Use + + + +```C# +using System; +using Microsoft.Extensions.Configuration; + +class Program +{ + static void Main() + { + // Build a configuration object from INI file + IConfiguration config = new ConfigurationBuilder() + .AddIniFile("appsettings.ini") + .Build(); + + // Get a configuration section + IConfigurationSection section = config.GetSection("Settings"); + + // Read configuration values + Console.WriteLine($"Server: {section["Server"]}"); + Console.WriteLine($"Database: {section["Database"]}"); + } +} +``` + +To run this example, include an `appsettings.ini` file with the following content in your project: + +``` +[Settings] +Server=example.com +Database=Northwind +``` + +You can include a configuration file using a code like this in your `.csproj` file: + +```xml + + + Always + + +``` + ## Additional Documentation diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md index b9f3878b7e9b78..b507e18c328a5e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md @@ -15,6 +15,7 @@ ## How to Use + ```C# using Microsoft.Extensions.Configuration; diff --git a/src/libraries/System.Collections.Immutable/src/PACKAGE.md b/src/libraries/System.Collections.Immutable/src/PACKAGE.md index 563660c9be59ea..202fb6d0137833 100644 --- a/src/libraries/System.Collections.Immutable/src/PACKAGE.md +++ b/src/libraries/System.Collections.Immutable/src/PACKAGE.md @@ -6,14 +6,6 @@ This package provides collections that are thread safe and guaranteed to never c The `System.Collections.Immutable` library is built-in as part of the shared framework in .NET Runtime. The package can be installed when you need to use it in other target frameworks. -## Key Features - - - -* -* -* - ## How to Use diff --git a/src/libraries/System.Reflection.Metadata/src/PACKAGE.md b/src/libraries/System.Reflection.Metadata/src/PACKAGE.md index df290dd1ab0f50..921506138ee1b4 100644 --- a/src/libraries/System.Reflection.Metadata/src/PACKAGE.md +++ b/src/libraries/System.Reflection.Metadata/src/PACKAGE.md @@ -83,9 +83,11 @@ class Program The main types provided by this library are: -* `` -* `` -* `` +* `System.Reflection.Metadata.MetadataReader` +* `System.Reflection.PortableExecutable.PEReader` +* `System.Reflection.Metadata.Ecma335.MetadataBuilder` +* `System.Reflection.PortableExecutable.PEBuilder` +* `System.Reflection.PortableExecutable.ManagedPEBuilder` ## Additional Documentation @@ -97,10 +99,6 @@ The main types provided by this library are: * [System.Reflection.PortableExecutable.PEBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.pebuilder) * [System.Reflection.PortableExecutable.ManagedPEBuilder](https://docs.microsoft.com/dotnet/api/system.reflection.portableexecutable.managedpebuilder) -## Related Packages - - - ## Feedback & Contributing From 934eeea33d3accc9f6811bf63315b456889242c7 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 16:00:28 +0200 Subject: [PATCH 257/345] ConfigurationManager clean-up --- .../System.Configuration.ConfigurationManager/src/PACKAGE.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md b/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md index 3a315884484cae..992b7669426993 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md +++ b/src/libraries/System.Configuration.ConfigurationManager/src/PACKAGE.md @@ -79,10 +79,6 @@ The main types provided by this library are: * [System.Configuration.Configuration](https://docs.microsoft.com/dotnet/api/system.configuration.configuration) * [System.Configuration.ConfigurationManager](https://docs.microsoft.com/dotnet/api/system.configuration.configurationmanager) -## Related Packages - - - ## Feedback & Contributing From f4d90741507cdef6304834ceffee0ab023c1b729 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 18 Sep 2023 16:33:59 +0200 Subject: [PATCH 258/345] Last clean-up --- .../Microsoft.Extensions.Configuration/src/PACKAGE.md | 1 - .../Microsoft.Extensions.Logging.Debug/src/PACKAGE.md | 1 - src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md | 1 + src/libraries/System.Data.Odbc/src/PACKAGE.md | 3 +++ src/libraries/System.Data.OleDb/src/PACKAGE.md | 3 +++ .../System.DirectoryServices.AccountManagement/src/PACKAGE.md | 1 - src/libraries/System.DirectoryServices/src/PACKAGE.md | 1 - src/libraries/System.IO.Ports/src/PACKAGE.md | 1 + src/libraries/System.Management/src/PACKAGE.md | 1 + src/libraries/System.Speech/src/PACKAGE.md | 1 + src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md | 2 +- 11 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md index b507e18c328a5e..1d193afbda8667 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Configuration/src/PACKAGE.md @@ -75,7 +75,6 @@ The main types provided by this library are: * [Microsoft.Extensions.Configuration.UserSecrets](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.UserSecrets) * [Microsoft.Extensions.Configuration.Xml](https://www.nuget.org/packages/Microsoft.Extensions.Configuration.Xml) - ## Feedback & Contributing diff --git a/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md index 8a5c652290643e..97b378f4350c57 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging.Debug/src/PACKAGE.md @@ -3,7 +3,6 @@ `Microsoft.Extensions.Logging.Debug` provides a Debug output logger provider implementation for Microsoft.Extensions.Logging. This logger logs messages to a debugger monitor by writing messages with `System.Diagnostics.Debug.WriteLine()`. - ## Key Features diff --git a/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md b/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md index 607283d3eb7486..87c2d2b79ee29d 100644 --- a/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md +++ b/src/libraries/Microsoft.Extensions.Logging/src/PACKAGE.md @@ -1,6 +1,7 @@ ## About + `Microsoft.Extensions.Logging` is combined with a core logging abstraction under `Microsoft.Extensions.Logging.Abstractions`. This abstraction is available in our basic built-in implementations like console, event log, and debug (Debug.WriteLine) logging. ## Key Features diff --git a/src/libraries/System.Data.Odbc/src/PACKAGE.md b/src/libraries/System.Data.Odbc/src/PACKAGE.md index 7195ca77a50064..a45dd52364c18e 100644 --- a/src/libraries/System.Data.Odbc/src/PACKAGE.md +++ b/src/libraries/System.Data.Odbc/src/PACKAGE.md @@ -11,6 +11,9 @@ Allows access to ODBC data sources. This is a basic example of retrieving the results of a query using an [OdbcDataReader](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcdatareader). For examples of using an [OdbcDataAdapter](https://learn.microsoft.com/dotnet/api/system.data.odbc.odbcdataadapter), and of updating an ODBC data source, please see the documentation. ```cs +using System.Data.Odbc; + +string connectionString = ""; string queryString = "SELECT DISTINCT CustomerID FROM Orders"; using OdbcConnection connection = new OdbcConnection(connectionString); diff --git a/src/libraries/System.Data.OleDb/src/PACKAGE.md b/src/libraries/System.Data.OleDb/src/PACKAGE.md index be973625ebef7d..6e81daa638b2eb 100644 --- a/src/libraries/System.Data.OleDb/src/PACKAGE.md +++ b/src/libraries/System.Data.OleDb/src/PACKAGE.md @@ -11,6 +11,9 @@ Allows access to legacy OLE DB data sources. This is a basic example of retrieving the results of a query using an [OleDbDataReader](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbdatareader). For examples of using an [OleDbDataAdapter](https://learn.microsoft.com/dotnet/api/system.data.oledb.oledbdataadapter), and of updating an OLE DB data source, please see the documentation. ```cs +using System.Data.OleDb; + +string connectionString = ""; string queryString = "SELECT OrderID, CustomerID FROM Orders"; using OleDbConnection connection = new OleDbConnection(connectionString); diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md index 7d761e089fbb8c..bee50af73d3c45 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/PACKAGE.md @@ -67,7 +67,6 @@ The main types provided by this library are: [System.DirectoryServices](https://learn.microsoft.com/dotnet/api/system.directoryservices) - ## Feedback & Contributing diff --git a/src/libraries/System.DirectoryServices/src/PACKAGE.md b/src/libraries/System.DirectoryServices/src/PACKAGE.md index 4c879dd574aa3e..981c865baf9210 100644 --- a/src/libraries/System.DirectoryServices/src/PACKAGE.md +++ b/src/libraries/System.DirectoryServices/src/PACKAGE.md @@ -69,7 +69,6 @@ The main types provided by this library are: * [Active Directory Service Interfaces](https://learn.microsoft.com/windows/win32/adsi/active-directory-service-interfaces-adsi) * [Lightweight Directory Access Protocol (LDAP)](https://learn.microsoft.com/previous-versions/windows/desktop/ldap/lightweight-directory-access-protocol-ldap-api) - ## Related Packages * [System.DirectoryServices.AccountManagement](https://learn.microsoft.com/dotnet/api/system.directoryservices.accountmanagement) diff --git a/src/libraries/System.IO.Ports/src/PACKAGE.md b/src/libraries/System.IO.Ports/src/PACKAGE.md index 90da18ddefd2f0..218bf288eb0454 100644 --- a/src/libraries/System.IO.Ports/src/PACKAGE.md +++ b/src/libraries/System.IO.Ports/src/PACKAGE.md @@ -1,6 +1,7 @@ ## About + [System.IO.Ports](https://www.nuget.org/packages/System.IO.Ports) package provides synchronous serial port file resource. Additionally, the functionality of this class can be wrapped in an internal `Stream` object, accessible through the `BaseStream` property, and passed to classes that wrap or use streams. ## Key Features diff --git a/src/libraries/System.Management/src/PACKAGE.md b/src/libraries/System.Management/src/PACKAGE.md index 280347191d1013..7138378ac87480 100644 --- a/src/libraries/System.Management/src/PACKAGE.md +++ b/src/libraries/System.Management/src/PACKAGE.md @@ -1,6 +1,7 @@ ## About + Provides access to a rich set of management information and management events about the system, devices, and applications instrumented to the Windows Management Instrumentation (WMI) infrastructure. Not supported on other platforms. ## Key Features diff --git a/src/libraries/System.Speech/src/PACKAGE.md b/src/libraries/System.Speech/src/PACKAGE.md index e7d46cc047307e..ac57df4ca354d8 100644 --- a/src/libraries/System.Speech/src/PACKAGE.md +++ b/src/libraries/System.Speech/src/PACKAGE.md @@ -1,6 +1,7 @@ ## About + Provides APIs for speech recognition and synthesis built on the [Microsoft Speech API](https://learn.microsoft.com/previous-versions/windows/desktop/ms723627(v=vs.85)) in Windows. Not supported on other platforms. This package is provided primarily for compatibility with code being ported from .NET Framework and is not accepting new features. diff --git a/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md b/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md index 87e4c8054b2fd6..7da4fd98cd740b 100644 --- a/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md +++ b/src/libraries/System.Text.Encoding.CodePages/src/PACKAGE.md @@ -8,7 +8,7 @@ ## How to Use -```csharp +```C# using System.Text; // Register the CodePages encoding provider at application startup to enable using single and double byte encodings. From bcdff134478ad8df8014018cc4a2e67cc34fc452 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:09:53 -0700 Subject: [PATCH 259/345] [release/8.0] Remove public provider from rundown session (#92048) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add rundown check * Update ep-session.c * Check for rundown provider * Fix * Update src/mono/mono/eventpipe/ep-rt-types-mono.h Co-authored-by: Aleksey Kliger (λgeek) * Fix cross plat build * Revert previous changes * Remove public provider from rundown session * Finish reverting * Update ep-session.c --------- Co-authored-by: David Mason Co-authored-by: Aleksey Kliger (λgeek) --- src/native/eventpipe/ep-session.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/native/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c index 959214d1375963..ee134be65059d7 100644 --- a/src/native/eventpipe/ep-session.c +++ b/src/native/eventpipe/ep-session.c @@ -329,24 +329,16 @@ ep_session_enable_rundown (EventPipeSession *session) const uint64_t keywords = 0x80020139; const EventPipeEventLevel verbose_logging_level = EP_EVENT_LEVEL_VERBOSE; - EventPipeProviderConfiguration rundown_providers [2]; - uint32_t rundown_providers_len = (uint32_t)ARRAY_SIZE (rundown_providers); + EventPipeProviderConfiguration rundown_provider; + ep_provider_config_init (&rundown_provider, ep_config_get_rundown_provider_name_utf8 (), keywords, verbose_logging_level, NULL); // Rundown provider. - ep_provider_config_init (&rundown_providers [0], ep_config_get_public_provider_name_utf8 (), keywords, verbose_logging_level, NULL); // Public provider. - ep_provider_config_init (&rundown_providers [1], ep_config_get_rundown_provider_name_utf8 (), keywords, verbose_logging_level, NULL); // Rundown provider. + EventPipeSessionProvider *session_provider = ep_session_provider_alloc ( + ep_provider_config_get_provider_name (&rundown_provider), + ep_provider_config_get_keywords (&rundown_provider), + ep_provider_config_get_logging_level (&rundown_provider), + ep_provider_config_get_filter_data (&rundown_provider)); - // Update provider list with rundown configuration. - for (uint32_t i = 0; i < rundown_providers_len; ++i) { - const EventPipeProviderConfiguration *config = &rundown_providers [i]; - - EventPipeSessionProvider *session_provider = ep_session_provider_alloc ( - ep_provider_config_get_provider_name (config), - ep_provider_config_get_keywords (config), - ep_provider_config_get_logging_level (config), - ep_provider_config_get_filter_data (config)); - - ep_raise_error_if_nok (ep_session_add_session_provider (session, session_provider)); - } + ep_raise_error_if_nok (ep_session_add_session_provider (session, session_provider)); ep_session_set_rundown_enabled (session, true); result = true; From 607bbcae163feefe855004bd404cf5564b755cd8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:11:57 -0700 Subject: [PATCH 260/345] [release/8.0] Avoid marking property/event attributes multiple times (#92153) * Avoid marking property attributes multiple times * Fix test for nativeaot * Add issue link * Simplify test, fix bug for events, add more coverage * Fix event tests * Fix test for nativeaot NativeAot requires a call to GetCustomAttribute for the attributes to be kept. --------- Co-authored-by: Sven Boemer --- .../src/linker/Linker.Steps/MarkStep.cs | 7 +- .../illink/src/linker/Linker/Annotations.cs | 1 - .../DataFlow/AttributePropertyDataflow.cs | 118 +++++++++++++++++- .../TypeHierarchyReflectionWarnings.cs | 5 - .../RequiresCapability/BasicRequires.cs | 2 - .../RequiresCapability/RequiresOnAttribute.cs | 5 - .../RequiresCapability/RequiresOnClass.cs | 6 - 7 files changed, 118 insertions(+), 26 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 52fe64b3632559..d5923d135aa5b8 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3548,7 +3548,8 @@ protected virtual bool ShouldParseMethodBody (MethodDefinition method) protected internal void MarkProperty (PropertyDefinition prop, in DependencyInfo reason) { - Tracer.AddDirectDependency (prop, reason, marked: false); + if (!Annotations.MarkProcessed (prop, reason)) + return; using var propertyScope = ScopeStack.PushScope (new MessageOrigin (prop)); @@ -3559,8 +3560,8 @@ protected internal void MarkProperty (PropertyDefinition prop, in DependencyInfo protected internal virtual void MarkEvent (EventDefinition evt, in DependencyInfo reason) { - // Record the event without marking it in Annotations. - Tracer.AddDirectDependency (evt, reason, marked: false); + if (!Annotations.MarkProcessed (evt, reason)) + return; using var eventScope = ScopeStack.PushScope (new MessageOrigin (evt)); diff --git a/src/tools/illink/src/linker/Linker/Annotations.cs b/src/tools/illink/src/linker/Linker/Annotations.cs index 6576436b963cec..456af9fdf6ab1e 100644 --- a/src/tools/illink/src/linker/Linker/Annotations.cs +++ b/src/tools/illink/src/linker/Linker/Annotations.cs @@ -272,7 +272,6 @@ public bool IsProcessed (IMetadataTokenProvider provider) public bool MarkProcessed (IMetadataTokenProvider provider, in DependencyInfo reason) { - Debug.Assert (!(reason.Kind == DependencyKind.AlreadyMarked)); Tracer.AddDirectDependency (provider, reason, marked: true); // The item may or may not be pending. marked_pending.Remove (provider); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs index 91fdad3652d8fd..2167c1886fa235 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs @@ -17,15 +17,19 @@ class AttributePropertyDataflow [KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))] [KeptAttributeAttribute (typeof (TypeArrayAttribute))] [KeepsPublicConstructors (Type = typeof (ClassWithKeptPublicConstructor))] - [KeepsPublicMethods (Type = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+ClassWithKeptPublicMethods")] + [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+ClassWithKeptPublicMethods")] [KeepsPublicFields (Type = null, TypeName = null)] [TypeArray (Types = new Type[] { typeof (AttributePropertyDataflow) })] // Trimmer only for now - https://github.com/dotnet/linker/issues/2273 [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] public static void Main () { - typeof (AttributePropertyDataflow).GetMethod ("Main").GetCustomAttribute (typeof (KeepsPublicConstructorsAttribute)); - typeof (AttributePropertyDataflow).GetMethod ("Main").GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); + typeof (AttributePropertyDataflow).GetMethod (nameof (Main)).GetCustomAttribute (typeof (KeepsPublicConstructorsAttribute)); + typeof (AttributePropertyDataflow).GetMethod (nameof (Main)).GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); + RecursivePropertyDataFlow.Test (); + RecursiveEventDataFlow.Test (); + RecursiveFieldDataFlow.Test (); + RecursiveMethodDataFlow.Test (); } [Kept] @@ -57,7 +61,13 @@ public KeepsPublicMethodsAttribute () [Kept] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] - public string Type { get; [Kept] set; } + public Type Type { get; [Kept] set; } + + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + public string TypeName { get; [Kept] set; } } // Used to test null values @@ -83,6 +93,38 @@ public KeepsPublicFieldsAttribute () public string TypeName { get; [Kept] set; } } + [Kept] + [KeptBaseType (typeof (Attribute))] + class KeepsPublicPropertiesAttribute : Attribute + { + [Kept] + public KeepsPublicPropertiesAttribute () + { + } + + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] + public Type Type { get; [Kept] set; } + } + + [Kept] + [KeptBaseType (typeof (Attribute))] + class KeepsPublicEventsAttribute : Attribute + { + [Kept] + public KeepsPublicEventsAttribute () + { + } + + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] + public Type Type { get; [Kept] set; } + } + [Kept] class ClassWithKeptPublicConstructor { @@ -117,5 +159,73 @@ public TypeArrayAttribute () [Kept] public Type[] Types { get; [Kept] set; } } + + [Kept] + class RecursivePropertyDataFlow + { + [field: Kept] + [Kept] + [KeptAttributeAttribute (typeof (KeepsPublicPropertiesAttribute))] + [KeepsPublicProperties (Type = typeof (RecursivePropertyDataFlow))] + public static int Property { [Kept] get; [Kept] set; } + + [Kept] + public static void Test () + { + typeof (RecursivePropertyDataFlow).GetProperty (nameof (Property)).GetCustomAttribute (typeof (KeepsPublicPropertiesAttribute)); + Property = 0; + } + } + + [Kept] + class RecursiveEventDataFlow + { + [field: Kept] + [Kept] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + [KeptAttributeAttribute (typeof (KeepsPublicEventsAttribute))] + [KeepsPublicEvents (Type = typeof (RecursiveEventDataFlow))] + public static event EventHandler Event; + + [Kept] + public static void Test () + { + typeof (RecursiveEventDataFlow).GetEvent (nameof (Event)).GetCustomAttribute (typeof (KeepsPublicEventsAttribute)); + Event += (sender, e) => { }; + } + } + + [Kept] + class RecursiveFieldDataFlow + { + [Kept] + [KeptAttributeAttribute (typeof (KeepsPublicFieldsAttribute))] + [KeepsPublicFields (Type = typeof (RecursiveFieldDataFlow))] + public static int field; + + [Kept] + public static void Test () + { + typeof (RecursiveMethodDataFlow).GetField (nameof (field)).GetCustomAttribute (typeof (KeepsPublicFieldsAttribute)); + field = 0; + } + } + + [Kept] + class RecursiveMethodDataFlow + { + [Kept] + [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] + [KeepsPublicMethods (Type = typeof (RecursiveMethodDataFlow))] + public static void Method () { } + + [Kept] + public static void Test () + { + typeof (RecursiveMethodDataFlow).GetMethod (nameof (Method)).GetCustomAttribute (typeof (KeepsPublicMethodsAttribute)); + Method (); + } + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs index a0d84562dd8917..d7225a40eacdb1 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs @@ -246,11 +246,6 @@ class AnnotatedPublicEvents public delegate void MyEventHandler (object sender, int i); [Kept] - // ILLink always keeps event methods when an event is kept, so this generates warnings - // on the event itself (since an event access is considered to reference the annotated add method), - // and on the add method (if it is accessed through reflection). - [ExpectedWarning ("IL2026", "--RUC on add_RUCEvent--", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "--RUC on add_RUCEvent--", ProducedBy = Tool.Trimmer)] [ExpectedWarning ("IL2026", "--RUC on add_RUCEvent--", ProducedBy = Tool.Trimmer)] public event MyEventHandler RUCEvent { [Kept] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs index ba11e7fa07fdef..0d6b360ac71478 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs @@ -137,7 +137,6 @@ static void TestRequiresFromNameOf () class OnEventMethod { - [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--", ProducedBy = Tool.Trimmer)] [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--", ProducedBy = Tool.Trimmer)] static event EventHandler EventToTestRemove { add { } @@ -147,7 +146,6 @@ static event EventHandler EventToTestRemove { remove { } } - [ExpectedWarning ("IL2026", "--EventToTestAdd.add--", ProducedBy = Tool.Trimmer)] [ExpectedWarning ("IL2026", "--EventToTestAdd.add--", ProducedBy = Tool.Trimmer)] static event EventHandler EventToTestAdd { [RequiresUnreferencedCode ("Message for --EventToTestAdd.add--")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs index d44fb0f4466fae..8710ed0e45cf82 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs @@ -112,14 +112,9 @@ static void MethodWithAttributeWhichRequires () { } static int _fieldWithAttributeWhichRequires; [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - // https://github.com/dotnet/runtime/issues/83581 - [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access - [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access - [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [AttributeWhichRequires] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs index c95e7abe6fa65b..abc594d1777390 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs @@ -494,8 +494,6 @@ class MemberTypesWithRequires // These should not be reported https://github.com/mono/linker/issues/2218 [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.add", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.add", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.remove", ProducedBy = Tool.Trimmer)] [ExpectedWarning ("IL2026", "MemberTypesWithRequires.Event.remove", ProducedBy = Tool.Trimmer)] public static event EventHandler Event; } @@ -851,10 +849,6 @@ class WithRequires // These should be reported only in TestDirectReflectionAccess // https://github.com/mono/linker/issues/2218 [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "StaticEvent.remove", ProducedBy = Tool.Trimmer)] - [ExpectedWarning ("IL2026", "StaticEvent.remove", ProducedBy = Tool.Trimmer)] [ExpectedWarning ("IL2026", "StaticEvent.remove", ProducedBy = Tool.Trimmer)] public static event EventHandler StaticEvent; } From 8ca963c0f88f328c420c0eb600f0d0169899d704 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:13:31 -0700 Subject: [PATCH 261/345] [workloads] Opt into using package groups (#92168) This is to make sure the MSI's we generate for VS are recognized as the same. Enabling sxs workloads by itself caused the package id's that wrap the manifest MSI's to be different. This prevents that from happening. Co-authored-by: Steve Pfister --- src/workloads/workloads.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workloads/workloads.csproj b/src/workloads/workloads.csproj index ae0a4f6af7f246..82c5c31badd71b 100644 --- a/src/workloads/workloads.csproj +++ b/src/workloads/workloads.csproj @@ -165,7 +165,7 @@ - Date: Mon, 18 Sep 2023 10:20:30 -0700 Subject: [PATCH 262/345] [release/8.0] Update dependencies from dnceng/internal/dotnet-optimization (#92177) * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230915.3 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23464.6 -> To Version 1.0.0-prerelease.23465.3 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230915.3 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23464.6 -> To Version 1.0.0-prerelease.23465.3 * Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230915.3 optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23464.6 -> To Version 1.0.0-prerelease.23465.3 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index da204b55f24849..161eab1c82c64c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 1d451c32dda2314c721adbf8829e1c0cd4e681ff - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 5b0a8abbba75c63e20e42f778650dd1448aef62c + f67c4e806a744f7274aed9493e4c8d39a3c73445 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 5b0a8abbba75c63e20e42f778650dd1448aef62c + f67c4e806a744f7274aed9493e4c8d39a3c73445 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 5b0a8abbba75c63e20e42f778650dd1448aef62c + f67c4e806a744f7274aed9493e4c8d39a3c73445 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 5b0a8abbba75c63e20e42f778650dd1448aef62c + f67c4e806a744f7274aed9493e4c8d39a3c73445 https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 5b0a8abbba75c63e20e42f778650dd1448aef62c + f67c4e806a744f7274aed9493e4c8d39a3c73445 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - 5b0a8abbba75c63e20e42f778650dd1448aef62c + f67c4e806a744f7274aed9493e4c8d39a3c73445 diff --git a/eng/Versions.props b/eng/Versions.props index 9223996861d8fd..f71e6cc183dd73 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -156,12 +156,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23464.6 - 1.0.0-prerelease.23464.6 - 1.0.0-prerelease.23464.6 - 1.0.0-prerelease.23464.6 - 1.0.0-prerelease.23464.6 - 1.0.0-prerelease.23464.6 + 1.0.0-prerelease.23465.3 + 1.0.0-prerelease.23465.3 + 1.0.0-prerelease.23465.3 + 1.0.0-prerelease.23465.3 + 1.0.0-prerelease.23465.3 + 1.0.0-prerelease.23465.3 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 From ae998ebf0071b0f441c7faca24165fe33530af8a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:21:39 -0700 Subject: [PATCH 263/345] [mono][aot] Avoid compiling the same method multiple times during dedup. (#92178) Co-authored-by: Zoltan Varga --- src/mono/mono/mini/aot-compiler.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 023cd6ce42b0b5..e067d2714d8a37 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -4326,6 +4326,7 @@ get_method_index (MonoAotCompile *acfg, MonoMethod *method) return index - 1; } +/* Return TRUE if the method can be skipped */ static gboolean collect_dedup_method (MonoAotCompile *acfg, MonoMethod *method) { @@ -4334,14 +4335,16 @@ collect_dedup_method (MonoAotCompile *acfg, MonoMethod *method) if (acfg->dedup_phase == DEDUP_SKIP) return TRUE; // Remember for later - if (acfg->dedup_phase == DEDUP_COLLECT && !g_hash_table_lookup (dedup_methods, method)) + g_assert (acfg->dedup_phase == DEDUP_COLLECT); + if (!g_hash_table_lookup (dedup_methods, method)) g_hash_table_insert (dedup_methods, method, method); + else + // Already processed when compiling another assembly + return TRUE; } return FALSE; } - - static int add_method_full (MonoAotCompile *acfg, MonoMethod *method, gboolean extra, int depth) { From 6c9a74307070bd63e2d88ae2e5d6aa03d46debf2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:22:10 -0700 Subject: [PATCH 264/345] [release/8.0] [browser] Add link to docs to interop error messages (#92182) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * JS part * C# part --------- Co-authored-by: Marek Fišera --- .../JSImportGenerator/Resources/Strings.resx | 26 +++++------ .../tests/JSImportGenerator.UnitTest/Fails.cs | 44 +++++++++---------- src/mono/wasm/runtime/marshal-to-cs.ts | 7 +-- src/mono/wasm/runtime/marshal-to-js.ts | 18 ++++---- 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx index b06ebce2260316..1c6e47ef214f15 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx @@ -136,7 +136,7 @@ Specified type is not supported by source-generated JavaScript interop. - {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} The generated source will not handle marshalling of the return value of method '{1}'. For more information see https://aka.ms/dotnet-wasm-jsinterop {0} is a message containing additional details about what is not supported {1} is the name of the method @@ -144,21 +144,21 @@ Type is not supported by source-generated JavaScript interop. - The type '{0}' is not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter '{1}'. + The type '{0}' is not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter '{1}'. For more information see https://aka.ms/dotnet-wasm-jsinterop - The type '{0}' is not supported by source-generated JavaScript interop. The generated source will not handle marshalling of the return value of method '{1}'. + The type '{0}' is not supported by source-generated JavaScript interop. The generated source will not handle marshalling of the return value of method '{1}'. For more information see https://aka.ms/dotnet-wasm-jsinterop - {0} The generated source will not handle marshalling of parameter '{1}'. + {0} The generated source will not handle marshalling of parameter '{1}'. For more information see https://aka.ms/dotnet-wasm-jsinterop {0} is a message containing additional details about what is not supported {1} is the name of the parameter - The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated JavaScript interop. + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated JavaScript interop. For more information see https://aka.ms/dotnet-wasm-jsinterop - The specified '{0}' configuration for parameter '{1}' is not supported by source-generated JavaScript interop. + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated JavaScript interop. For more information see https://aka.ms/dotnet-wasm-jsinterop Invalid 'JSImportAttribute' usage @@ -167,10 +167,10 @@ Invalid 'JSExportAttribute' usage - Method '{0}' should be 'static', 'partial', and non-generic when marked with 'JSImportAttribute'. JavaScript interop source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'JSImportAttribute'. JavaScript interop source generation will ignore method '{0}'. For more information see https://aka.ms/dotnet-wasm-jsinterop - Method '{0}' should be 'static', non-partial and non-generic when marked with 'JSExportAttribute'. JavaScript interop source generation will ignore method '{0}'. + Method '{0}' should be 'static', non-partial and non-generic when marked with 'JSExportAttribute'. JavaScript interop source generation will ignore method '{0}'. For more information see https://aka.ms/dotnet-wasm-jsinterop Methods marked with 'JSImportAttribute' should be 'static', 'partial', and non-generic. JavaScript interop source generation will ignore methods that are non-'static', non-'partial', or generic. @@ -179,7 +179,7 @@ Methods marked with 'JSImportAttribute' should be 'static', non-partial, and non-generic. JavaScript interop source generation will ignore methods that are non-'static', 'partial', or generic. - Method '{0}' is contained in a type '{1}' that is not marked 'partial'. JavaScript interop source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. JavaScript interop source generation will ignore method '{0}'. For more information see https://aka.ms/dotnet-wasm-jsinterop 'JSType.Discard' could be only used with void return argument. @@ -212,18 +212,18 @@ JSImportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. - JSImportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. + JSImportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. For more information see https://aka.ms/dotnet-wasm-jsinterop - JSImportAttribute requires unsafe code. + JSImportAttribute requires unsafe code. For more information see https://aka.ms/dotnet-wasm-jsinterop JSExportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. - JSExportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. + JSExportAttribute requires unsafe code. Project must be updated with '<AllowUnsafeBlocks>true</AllowUnsafeBlocks>'. For more information see https://aka.ms/dotnet-wasm-jsinterop - JSExportAttribute requires unsafe code. + JSExportAttribute requires unsafe code. For more information see https://aka.ms/dotnet-wasm-jsinterop \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs index 513af4747a4e92..f5ffe77afb7949 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs @@ -15,39 +15,39 @@ public class Fails public static IEnumerable CodeSnippetsToFail() { yield return new object?[] { CodeSnippets.DefaultReturnMarshaler(), new string[] { - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of the return value of method 'Import1'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of the return value of method 'Export1'.", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of the return value of method 'Import1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of the return value of method 'Export1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", },null }; yield return new object?[] { CodeSnippets.DefaultReturnMarshaler(), null, null }; yield return new object?[] { CodeSnippets.DefaultReturnMarshaler("System.Func"), null, null }; yield return new object?[] { CodeSnippets.DefaultReturnMarshaler("System.Action"), new string[] { - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Action. The generated source will not handle marshalling of the return value of method 'Import1'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Action. The generated source will not handle marshalling of the return value of method 'Export1'.", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Action. The generated source will not handle marshalling of the return value of method 'Import1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Action. The generated source will not handle marshalling of the return value of method 'Export1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", },null }; yield return new object?[] { CodeSnippets.DefaultReturnMarshaler("System.Span"), null, null }; yield return new object?[] { CodeSnippets.DefaultReturnMarshaler("System.Span"), null, null }; yield return new object?[] { CodeSnippets.DefaultReturnMarshaler("System.ArraySegment"), null, null }; yield return new object?[] { CodeSnippets.AllMissing, new string[] { - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of object. The generated source will not handle marshalling of parameter 'a1'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of parameter 'a2'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of parameter 'a3'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Action. The generated source will not handle marshalling of parameter 'a4'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Func. The generated source will not handle marshalling of parameter 'a5'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Span. The generated source will not handle marshalling of parameter 'a6'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.ArraySegment. The generated source will not handle marshalling of parameter 'a7'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a8'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of object[]. The generated source will not handle marshalling of parameter 'a9'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.DateTime. The generated source will not handle marshalling of parameter 'a10'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.DateTimeOffset. The generated source will not handle marshalling of parameter 'a11'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a12'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a13'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a14'.", - "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a15'.", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of object. The generated source will not handle marshalling of parameter 'a1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of parameter 'a2'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of long. The generated source will not handle marshalling of parameter 'a3'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Action. The generated source will not handle marshalling of parameter 'a4'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Func. The generated source will not handle marshalling of parameter 'a5'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Span. The generated source will not handle marshalling of parameter 'a6'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.ArraySegment. The generated source will not handle marshalling of parameter 'a7'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a8'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of object[]. The generated source will not handle marshalling of parameter 'a9'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.DateTime. The generated source will not handle marshalling of parameter 'a10'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.DateTimeOffset. The generated source will not handle marshalling of parameter 'a11'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a12'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a13'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a14'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a15'. For more information see https://aka.ms/dotnet-wasm-jsinterop", },null }; yield return new object?[] { CodeSnippets.InOutRef, new string[] { - "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a1'.", - "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a2'.", - "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a3'.", + "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a2'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a3'. For more information see https://aka.ms/dotnet-wasm-jsinterop", }, null }; } diff --git a/src/mono/wasm/runtime/marshal-to-cs.ts b/src/mono/wasm/runtime/marshal-to-cs.ts index a0f5b58a5cd332..14d6c7e3dd7479 100644 --- a/src/mono/wasm/runtime/marshal-to-cs.ts +++ b/src/mono/wasm/runtime/marshal-to-cs.ts @@ -24,6 +24,7 @@ import { TypedArray } from "./types/emscripten"; import { addUnsettledPromise, settleUnsettledPromise } from "./pthreads/shared/eventloop"; import { mono_log_warn } from "./logging"; +export const jsinteropDoc = "For more information see https://aka.ms/dotnet-wasm-jsinterop"; export function initialize_marshalers_to_cs(): void { if (js_to_cs_marshalers.size == 0) { @@ -389,7 +390,7 @@ export function marshal_js_object_to_cs(arg: JSMarshalerArgument, value: any): v } else { // if value was ManagedObject, it would be double proxied, but the C# signature requires that - mono_check(value[js_owned_gc_handle_symbol] === undefined, "JSObject proxy of ManagedObject proxy is not supported"); + mono_check(value[js_owned_gc_handle_symbol] === undefined, () => `JSObject proxy of ManagedObject proxy is not supported. ${jsinteropDoc}`); mono_check(typeof value === "function" || typeof value === "object", () => `JSObject proxy of ${typeof value} is not supported`); set_arg_type(arg, MarshalerType.JSObject); @@ -474,7 +475,7 @@ function _marshal_cs_object_to_cs(arg: JSMarshalerArgument, value: any): void { else { assert_not_disposed(value); if (value instanceof ArraySegment) { - throw new Error("NotImplementedException: ArraySegment"); + throw new Error("NotImplementedException: ArraySegment. " + jsinteropDoc); } else if (value instanceof ManagedError) { set_arg_type(arg, MarshalerType.Exception); @@ -484,7 +485,7 @@ function _marshal_cs_object_to_cs(arg: JSMarshalerArgument, value: any): void { set_arg_type(arg, MarshalerType.Object); set_gc_handle(arg, gc_handle); } else { - throw new Error("NotImplementedException " + js_type); + throw new Error("NotImplementedException " + js_type + ". " + jsinteropDoc); } } } diff --git a/src/mono/wasm/runtime/marshal-to-js.ts b/src/mono/wasm/runtime/marshal-to-js.ts index 9b5a931067fda6..1ad71dbc4ae784 100644 --- a/src/mono/wasm/runtime/marshal-to-js.ts +++ b/src/mono/wasm/runtime/marshal-to-js.ts @@ -18,7 +18,7 @@ import { import { monoStringToString } from "./strings"; import { JSHandleNull, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToJs, MarshalerType } from "./types/internal"; import { TypedArray } from "./types/emscripten"; -import { get_marshaler_to_cs_by_type } from "./marshal-to-cs"; +import { get_marshaler_to_cs_by_type, jsinteropDoc } from "./marshal-to-cs"; import { localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory"; export function initialize_marshalers_to_js(): void { @@ -85,7 +85,7 @@ export function get_marshaler_to_js_by_type(marshaler_type: MarshalerType): Mars return undefined; } const converter = cs_to_js_marshalers.get(marshaler_type); - mono_assert(converter && typeof converter === "function", () => `ERR41: Unknown converter for type ${marshaler_type}`); + mono_assert(converter && typeof converter === "function", () => `ERR41: Unknown converter for type ${marshaler_type}. ${jsinteropDoc}`); return converter; } @@ -224,7 +224,7 @@ export function marshal_task_to_js(arg: JSMarshalerArgument, _?: MarshalerType, // when we arrived here from _marshal_cs_object_to_js res_converter = cs_to_js_marshalers.get(type); } - mono_assert(res_converter, () => `Unknown sub_converter for type ${MarshalerType[type]} `); + mono_assert(res_converter, () => `Unknown sub_converter for type ${MarshalerType[type]}. ${jsinteropDoc}`); // this is already resolved const val = res_converter(arg); @@ -256,7 +256,7 @@ export function marshal_task_to_js(arg: JSMarshalerArgument, _?: MarshalerType, // when we arrived here from _marshal_cs_object_to_js res_converter = cs_to_js_marshalers.get(type); } - mono_assert(res_converter, () => `Unknown sub_converter for type ${MarshalerType[type]}`); + mono_assert(res_converter, () => `Unknown sub_converter for type ${MarshalerType[type]}. ${jsinteropDoc}`); const js_value = res_converter!(argInner); orig_resolve(js_value); @@ -291,7 +291,7 @@ export function mono_wasm_marshal_promise(args: JSMarshalerArguments): void { else if (value_type !== MarshalerType.Task) { // this is already resolved task const sub_converter = cs_to_js_marshalers.get(value_type); - mono_assert(sub_converter, () => `Unknown sub_converter for type ${MarshalerType[value_type]} `); + mono_assert(sub_converter, () => `Unknown sub_converter for type ${MarshalerType[value_type]}. ${jsinteropDoc}`); const data = sub_converter(arg_value); promise_control.resolve(data); } @@ -406,7 +406,7 @@ function _marshal_cs_object_to_js(arg: JSMarshalerArgument): any { // other types const converter = cs_to_js_marshalers.get(marshaler_type); - mono_assert(converter, () => `Unknown converter for type ${MarshalerType[marshaler_type]}`); + mono_assert(converter, () => `Unknown converter for type ${MarshalerType[marshaler_type]}. ${jsinteropDoc}`); return converter(arg); } @@ -461,7 +461,7 @@ function _marshal_array_to_js_impl(arg: JSMarshalerArgument, element_type: Marsh result = sourceView.slice();//copy } else { - throw new Error(`NotImplementedException ${MarshalerType[element_type]} `); + throw new Error(`NotImplementedException ${MarshalerType[element_type]}. ${jsinteropDoc}`); } Module._free(buffer_ptr); return result; @@ -483,7 +483,7 @@ function _marshal_span_to_js(arg: JSMarshalerArgument, element_type?: MarshalerT result = new Span(buffer_ptr, length, MemoryViewType.Double); } else { - throw new Error(`NotImplementedException ${MarshalerType[element_type]} `); + throw new Error(`NotImplementedException ${MarshalerType[element_type]}. ${jsinteropDoc}`); } return result; } @@ -504,7 +504,7 @@ function _marshal_array_segment_to_js(arg: JSMarshalerArgument, element_type?: M result = new ArraySegment(buffer_ptr, length, MemoryViewType.Double); } else { - throw new Error(`NotImplementedException ${MarshalerType[element_type]} `); + throw new Error(`NotImplementedException ${MarshalerType[element_type]}. ${jsinteropDoc}`); } const gc_handle = get_arg_gc_handle(arg); if (BuildConfiguration === "Debug") { From db172b4c55e362dac8c2f253c6260caa372a745d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:23:48 -0700 Subject: [PATCH 265/345] JIT: Extract all side effects of the index in optRemoveRangeCheck (#92210) optRemoveRangeCheck extracts only GTF_ASG from the bounds check. If the BOUNDS_CHECK is complex, that results in silently dropping side effects on the floor (see the example case). The ideal fix is that we should always extract all side effects from the index and length operands, however this has large regressions because the length typically has an ARR_LENGTH that we then extract. This PR instead has a surgical fix for the problem case that can be backported to .NET 8. It extracts all side effects from the index, but keeps extracting only GTF_ASG from the length to get around the issue mentioned above. Fix #91862 Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/optimizer.cpp | 10 +++- .../JitBlue/Runtime_91576/Runtime_91576.cs | 2 +- .../JitBlue/Runtime_91862/Runtime_91862.cs | 46 +++++++++++++++++++ .../Runtime_91862/Runtime_91862.csproj | 8 ++++ 4 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.csproj diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 7c99a6a423dd01..2ca5526476b82d 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -8875,9 +8875,15 @@ GenTree* Compiler::optRemoveRangeCheck(GenTreeBoundsChk* check, GenTree* comma, } #endif - // Extract side effects + // TODO-Bug: We really should be extracting all side effects from the + // length and index here, but the length typically involves a GT_ARR_LENGTH + // that we would preserve. Usually, as part of proving that the range check + // passes, we have also proven that the ARR_LENGTH is non-faulting. We need + // a good way to communicate to this function that it is ok to ignore side + // effects of the ARR_LENGTH. GenTree* sideEffList = nullptr; - gtExtractSideEffList(check, &sideEffList, GTF_ASG); + gtExtractSideEffList(check->GetArrayLength(), &sideEffList, GTF_ASG); + gtExtractSideEffList(check->GetIndex(), &sideEffList); if (sideEffList != nullptr) { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs index 4df185d99ab241..23ae4b41c76a28 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91576/Runtime_91576.cs @@ -1,5 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license.aa +// The .NET Foundation licenses this file to you under the MIT license. // Generated by Fuzzlyn v1.6 on 2023-09-03 15:59:01 // Run on X64 Windows diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.cs new file mode 100644 index 00000000000000..541e2658f2d6a3 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public class Runtime_91862 +{ + [Fact] + public static int TestEntryPoint() + { + return Foo(default); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Foo(Vector128 v) + { + int result = 101; + // This tree results in a BOUNDS_CHECK for Bar(...) & 3 + float x = Vector128.GetElement(v, Bar(ref result) & 3); + + if (result != 100) + { + Console.WriteLine("FAIL"); + } + + // After inlining x is DCE'd, which will extract side effects of its assignment above. + // That results IR amenable to forward sub, and we end up with a BOUNDS_CHECK + // with a complex index expression that we can still prove is within bounds. + Baz(x); + return result; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int Bar(ref int result) + { + result = 100; + return 0; + } + + private static void Baz(float x) + { + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91862/Runtime_91862.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 7226388ddf7657da0b29d3ed72bf4855f544e065 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Mon, 18 Sep 2023 19:24:19 +0200 Subject: [PATCH 266/345] [release/8.0] JIT: Initialize jitstdout lazily (#92212) * JIT: Initialize jitstdout lazily Avoid duplicating a handle and doing several I/O operations on the startup path. Fixes #91856 as a side effect. * Fix jitShutdown * Add volatile * CSE * Ensure jitstdout() is not used eagerly * Move comment, fix printf -> jitprintf * Clean up --- src/coreclr/jit/codegencommon.cpp | 6 +- src/coreclr/jit/compiler.cpp | 342 +++++++++++++++--------------- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/disasm.cpp | 6 +- src/coreclr/jit/ee_il_dll.cpp | 73 +++++-- src/coreclr/jit/emit.cpp | 4 +- src/coreclr/jit/error.cpp | 4 +- src/coreclr/jit/fgdiagnostic.cpp | 2 +- src/coreclr/jit/gentree.cpp | 4 +- src/coreclr/jit/gentree.h | 2 +- src/coreclr/jit/host.h | 5 +- src/coreclr/jit/inline.cpp | 2 +- src/coreclr/jit/lsra.cpp | 2 +- 13 files changed, 242 insertions(+), 212 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 07e03d3e0c2334..72e31c388154ab 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2011,7 +2011,7 @@ void CodeGen::genEmitMachineCode() #if TRACK_LSRA_STATS if (JitConfig.DisplayLsraStats() == 3) { - compiler->m_pLinearScan->dumpLsraStatsSummary(jitstdout); + compiler->m_pLinearScan->dumpLsraStatsSummary(jitstdout()); } #endif // TRACK_LSRA_STATS @@ -2104,7 +2104,7 @@ void CodeGen::genEmitUnwindDebugGCandEH() genCreateAndStoreGCInfo(codeSize, prologSize, epilogSize DEBUGARG(codePtr)); #ifdef DEBUG - FILE* dmpf = jitstdout; + FILE* dmpf = jitstdout(); compiler->opts.dmpHex = false; if (!strcmp(compiler->info.compMethodName, "= 0.5) { - fprintf(fout, " GT_%-17s %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName(oper.Oper), count, - percentage, size); + jitprintf(" GT_%-17s %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName(oper.Oper), count, + percentage, size); remainingCount -= count; } else @@ -1484,14 +1482,14 @@ void Compiler::compShutdown() if (remainingCount > 0) { - fprintf(fout, " All other GT_xxx ... %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", - remainingCount, 100.0 * remainingCount / totalCount, 100.0 * remainingCountSmall / totalCount, - 100.0 * remainingCountLarge / totalCount); + jitprintf(" All other GT_xxx ... %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", remainingCount, + 100.0 * remainingCount / totalCount, 100.0 * remainingCountSmall / totalCount, + 100.0 * remainingCountLarge / totalCount); } - fprintf(fout, " -----------------------------------------------------\n"); - fprintf(fout, " Total ....... %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", totalCount, - 100.0 * countSmall / totalCount, 100.0 * countLarge / totalCount); - fprintf(fout, "\n"); + jitprintf(" -----------------------------------------------------\n"); + jitprintf(" Total ....... %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", totalCount, + 100.0 * countSmall / totalCount, 100.0 * countLarge / totalCount); + jitprintf("\n"); } #endif // COUNT_AST_OPERS @@ -1500,49 +1498,49 @@ void Compiler::compShutdown() if (grossVMsize && grossNCsize) { - fprintf(fout, "\n"); - fprintf(fout, "--------------------------------------\n"); - fprintf(fout, "Function and GC info size stats\n"); - fprintf(fout, "--------------------------------------\n"); + jitprintf("\n"); + jitprintf("--------------------------------------\n"); + jitprintf("Function and GC info size stats\n"); + jitprintf("--------------------------------------\n"); - fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName, - 100 * grossNCsize / grossVMsize, "Total (excluding GC info)"); + jitprintf("[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName, + 100 * grossNCsize / grossVMsize, "Total (excluding GC info)"); - fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName, - 100 * totalNCsize / grossVMsize, "Total (including GC info)"); + jitprintf("[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName, + 100 * totalNCsize / grossVMsize, "Total (including GC info)"); if (gcHeaderISize || gcHeaderNSize) { - fprintf(fout, "\n"); + jitprintf("\n"); - fprintf(fout, "GC tables : [%7uI,%7uN] %7u byt (%u%% of IL, %u%% of %s).\n", - gcHeaderISize + gcPtrMapISize, gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize, - 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize, - Target::g_tgtCPUName); + jitprintf("GC tables : [%7uI,%7uN] %7u byt (%u%% of IL, %u%% of %s).\n", gcHeaderISize + gcPtrMapISize, + gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize, + 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize, + Target::g_tgtCPUName); - fprintf(fout, "GC headers : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize, - gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001), - (float)gcHeaderNSize / (genMethodNCnt + 0.001), - (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt); + jitprintf("GC headers : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize, + gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001), + (float)gcHeaderNSize / (genMethodNCnt + 0.001), + (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt); - fprintf(fout, "GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize, - gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001), - (float)gcPtrMapNSize / (genMethodNCnt + 0.001), - (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt); + jitprintf("GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize, + gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001), + (float)gcPtrMapNSize / (genMethodNCnt + 0.001), + (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt); } else { - fprintf(fout, "\n"); + jitprintf("\n"); - fprintf(fout, "GC tables take up %u bytes (%u%% of instr, %u%% of %6s code).\n", - totalNCsize - grossNCsize, 100 * (totalNCsize - grossNCsize) / grossVMsize, - 100 * (totalNCsize - grossNCsize) / grossNCsize, Target::g_tgtCPUName); + jitprintf("GC tables take up %u bytes (%u%% of instr, %u%% of %6s code).\n", totalNCsize - grossNCsize, + 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize, + Target::g_tgtCPUName); } #ifdef DEBUG #if DOUBLE_ALIGN - fprintf(fout, "%u out of %u methods generated with double-aligned stack\n", - Compiler::s_lvaDoubleAlignedProcsCount, genMethodCnt); + jitprintf("%u out of %u methods generated with double-aligned stack\n", Compiler::s_lvaDoubleAlignedProcsCount, + genMethodCnt); #endif #endif } @@ -1550,110 +1548,110 @@ void Compiler::compShutdown() #endif // DISPLAY_SIZES #if CALL_ARG_STATS - compDispCallArgStats(fout); + compDispCallArgStats(jitstdout()); #endif #if COUNT_BASIC_BLOCKS - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "Basic block count frequency table:\n"); - fprintf(fout, "--------------------------------------------------\n"); - bbCntTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "IL method size frequency table for methods with a single basic block:\n"); - fprintf(fout, "--------------------------------------------------\n"); - bbOneBBSizeTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "fgComputeDoms `while (change)` iterations:\n"); - fprintf(fout, "--------------------------------------------------\n"); - domsChangedIterationTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "fgComputeReachabilitySets `while (change)` iterations:\n"); - fprintf(fout, "--------------------------------------------------\n"); - computeReachabilitySetsIterationTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "fgComputeReachability `while (change)` iterations:\n"); - fprintf(fout, "--------------------------------------------------\n"); - computeReachabilityIterationTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); + jitprintf("--------------------------------------------------\n"); + jitprintf("Basic block count frequency table:\n"); + jitprintf("--------------------------------------------------\n"); + bbCntTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("IL method size frequency table for methods with a single basic block:\n"); + jitprintf("--------------------------------------------------\n"); + bbOneBBSizeTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("fgComputeDoms `while (change)` iterations:\n"); + jitprintf("--------------------------------------------------\n"); + domsChangedIterationTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("fgComputeReachabilitySets `while (change)` iterations:\n"); + jitprintf("--------------------------------------------------\n"); + computeReachabilitySetsIterationTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("fgComputeReachability `while (change)` iterations:\n"); + jitprintf("--------------------------------------------------\n"); + computeReachabilityIterationTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); #endif // COUNT_BASIC_BLOCKS #if COUNT_LOOPS - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Loop stats\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Total number of methods with loops is %5u\n", totalLoopMethods); - fprintf(fout, "Total number of loops is %5u\n", totalLoopCount); - fprintf(fout, "Maximum number of loops per method is %5u\n", maxLoopsPerMethod); - fprintf(fout, "# of methods overflowing nat loop table is %5u\n", totalLoopOverflows); - fprintf(fout, "Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount); - fprintf(fout, "# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows); - fprintf(fout, "Total number of loops with an iterator is %5u\n", iterLoopCount); - fprintf(fout, "Total number of loops with a constant iterator is %5u\n", constIterLoopCount); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "Loop count frequency table:\n"); - fprintf(fout, "--------------------------------------------------\n"); - loopCountTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "Loop exit count frequency table:\n"); - fprintf(fout, "--------------------------------------------------\n"); - loopExitCountTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Loop stats\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Total number of methods with loops is %5u\n", totalLoopMethods); + jitprintf("Total number of loops is %5u\n", totalLoopCount); + jitprintf("Maximum number of loops per method is %5u\n", maxLoopsPerMethod); + jitprintf("# of methods overflowing nat loop table is %5u\n", totalLoopOverflows); + jitprintf("Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount); + jitprintf("# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows); + jitprintf("Total number of loops with an iterator is %5u\n", iterLoopCount); + jitprintf("Total number of loops with a constant iterator is %5u\n", constIterLoopCount); + + jitprintf("--------------------------------------------------\n"); + jitprintf("Loop count frequency table:\n"); + jitprintf("--------------------------------------------------\n"); + loopCountTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + jitprintf("Loop exit count frequency table:\n"); + jitprintf("--------------------------------------------------\n"); + loopExitCountTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); #endif // COUNT_LOOPS #if MEASURE_NODE_SIZE - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "GenTree node allocation stats\n"); - fprintf(fout, "---------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("GenTree node allocation stats\n"); + jitprintf("---------------------------------------------------\n"); - fprintf(fout, "Allocated %6I64u tree nodes (%7I64u bytes total, avg %4I64u bytes per method)\n", - genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize, - genNodeSizeStats.genTreeNodeSize / genMethodCnt); + jitprintf("Allocated %6I64u tree nodes (%7I64u bytes total, avg %4I64u bytes per method)\n", + genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize, + genNodeSizeStats.genTreeNodeSize / genMethodCnt); - fprintf(fout, "Allocated %7I64u bytes of unused tree node space (%3.2f%%)\n", - genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize, - (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) / - genNodeSizeStats.genTreeNodeSize); + jitprintf("Allocated %7I64u bytes of unused tree node space (%3.2f%%)\n", + genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize, + (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) / + genNodeSizeStats.genTreeNodeSize); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of per-method GenTree node counts:\n"); - genTreeNcntHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of per-method GenTree node counts:\n"); + genTreeNcntHist.dump(jitstdout()); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of per-method GenTree node allocations (in bytes):\n"); - genTreeNsizHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of per-method GenTree node allocations (in bytes):\n"); + genTreeNsizHist.dump(jitstdout()); #endif // MEASURE_NODE_SIZE #if MEASURE_BLOCK_SIZE - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "BasicBlock and FlowEdge/BasicBlockList allocation stats\n"); - fprintf(fout, "---------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("BasicBlock and FlowEdge/BasicBlockList allocation stats\n"); + jitprintf("---------------------------------------------------\n"); - fprintf(fout, "Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count, - BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt); - fprintf(fout, "Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt, - genFlowNodeSize, genFlowNodeSize / genMethodCnt); + jitprintf("Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count, + BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt); + jitprintf("Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt, genFlowNodeSize, + genFlowNodeSize / genMethodCnt); #endif // MEASURE_BLOCK_SIZE @@ -1661,21 +1659,21 @@ void Compiler::compShutdown() if (s_dspMemStats) { - fprintf(fout, "\nAll allocations:\n"); - ArenaAllocator::dumpAggregateMemStats(jitstdout); + jitprintf("\nAll allocations:\n"); + ArenaAllocator::dumpAggregateMemStats(jitstdout()); - fprintf(fout, "\nLargest method:\n"); - ArenaAllocator::dumpMaxMemStats(jitstdout); + jitprintf("\nLargest method:\n"); + ArenaAllocator::dumpMaxMemStats(jitstdout()); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of total memory allocated per method (in KB):\n"); - memAllocHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of total memory allocated per method (in KB):\n"); + memAllocHist.dump(jitstdout()); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of total memory used per method (in KB):\n"); - memUsedHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of total memory used per method (in KB):\n"); + memUsedHist.dump(jitstdout()); } #endif // MEASURE_MEM_ALLOC @@ -1685,29 +1683,29 @@ void Compiler::compShutdown() if (JitConfig.DisplayLoopHoistStats() != 0) #endif // DEBUG { - PrintAggregateLoopHoistStats(jitstdout); + PrintAggregateLoopHoistStats(jitstdout()); } #endif // LOOP_HOIST_STATS #if TRACK_ENREG_STATS if (JitConfig.JitEnregStats() != 0) { - s_enregisterStats.Dump(fout); + s_enregisterStats.Dump(jitstdout()); } #endif // TRACK_ENREG_STATS #if MEASURE_PTRTAB_SIZE - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "GC pointer table stats\n"); - fprintf(fout, "---------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("GC pointer table stats\n"); + jitprintf("---------------------------------------------------\n"); - fprintf(fout, "Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize, - GCInfo::s_gcRegPtrDscSize / genMethodCnt); + jitprintf("Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize, + GCInfo::s_gcRegPtrDscSize / genMethodCnt); - fprintf(fout, "Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize, - GCInfo::s_gcTotalPtrTabSize / genMethodCnt); + jitprintf("Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize, + GCInfo::s_gcTotalPtrTabSize / genMethodCnt); #endif // MEASURE_PTRTAB_SIZE @@ -1715,37 +1713,37 @@ void Compiler::compShutdown() if (genMethodCnt != 0) { - fprintf(fout, "\n"); - fprintf(fout, "A total of %6u methods compiled", genMethodCnt); + jitprintf("\n"); + jitprintf("A total of %6u methods compiled", genMethodCnt); #if DISPLAY_SIZES if (genMethodICnt || genMethodNCnt) { - fprintf(fout, " (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt); + jitprintf(" (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt); } #endif // DISPLAY_SIZES - fprintf(fout, ".\n"); + jitprintf(".\n"); } #endif // MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES #if EMITTER_STATS - emitterStats(fout); + emitterStats(jitstdout()); #endif #if MEASURE_FATAL - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Fatal errors stats\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, " badCode: %u\n", fatal_badCode); - fprintf(fout, " noWay: %u\n", fatal_noWay); - fprintf(fout, " implLimitation: %u\n", fatal_implLimitation); - fprintf(fout, " NOMEM: %u\n", fatal_NOMEM); - fprintf(fout, " noWayAssertBody: %u\n", fatal_noWayAssertBody); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Fatal errors stats\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf(" badCode: %u\n", fatal_badCode); + jitprintf(" noWay: %u\n", fatal_noWay); + jitprintf(" implLimitation: %u\n", fatal_implLimitation); + jitprintf(" NOMEM: %u\n", fatal_NOMEM); + jitprintf(" noWayAssertBody: %u\n", fatal_noWayAssertBody); #ifdef DEBUG - fprintf(fout, " noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs); + jitprintf(" noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs); #endif // DEBUG - fprintf(fout, " NYI: %u\n", fatal_NYI); + jitprintf(" NYI: %u\n", fatal_NYI); #endif // MEASURE_FATAL } @@ -1754,14 +1752,14 @@ void Compiler::compShutdown() */ /* static */ -void Compiler::compDisplayStaticSizes(FILE* fout) +void Compiler::compDisplayStaticSizes() { #if MEASURE_NODE_SIZE - GenTree::DumpNodeSizes(fout); + GenTree::DumpNodeSizes(); #endif #if EMITTER_STATS - emitterStaticStats(fout); + emitterStaticStats(); #endif } @@ -5177,7 +5175,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl #if TRACK_LSRA_STATS if (JitConfig.DisplayLsraStats() == 2) { - m_pLinearScan->dumpLsraStatsCsv(jitstdout); + m_pLinearScan->dumpLsraStatsCsv(jitstdout()); } #endif // TRACK_LSRA_STATS @@ -5879,7 +5877,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr, } #endif // FUNC_INFO_LOGGING - // if (s_compMethodsCount==0) setvbuf(jitstdout, NULL, _IONBF, 0); + // if (s_compMethodsCount==0) setvbuf(jitstdout(), NULL, _IONBF, 0); if (compIsForInlining()) { @@ -6363,7 +6361,7 @@ void Compiler::compCompileFinish() if (s_dspMemStats || verbose) { printf("\nAllocations for %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash()); - compArenaAllocator->dumpMemStats(jitstdout); + compArenaAllocator->dumpMemStats(jitstdout()); } #endif // DEBUG #endif // MEASURE_MEM_ALLOC diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 645e54258a637a..8339d6d274f4f5 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -10345,7 +10345,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX InlineInfo* inlineInfo); void compDone(); - static void compDisplayStaticSizes(FILE* fout); + static void compDisplayStaticSizes(); //------------ Some utility functions -------------- diff --git a/src/coreclr/jit/disasm.cpp b/src/coreclr/jit/disasm.cpp index e1926a3f640b7b..fd5c98eb068810 100644 --- a/src/coreclr/jit/disasm.cpp +++ b/src/coreclr/jit/disasm.cpp @@ -1478,12 +1478,12 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCo } #else // !DEBUG // NOTE: non-DEBUG builds always use jitstdout currently! - disAsmFile = jitstdout; + disAsmFile = jitstdout(); #endif // !DEBUG if (disAsmFile == nullptr) { - disAsmFile = jitstdout; + disAsmFile = jitstdout(); } // As this writes to a common file, this is not reentrant. @@ -1519,7 +1519,7 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCo DisasmBuffer(disAsmFile, /* printIt */ true); fprintf(disAsmFile, "\n"); - if (disAsmFile != jitstdout) + if (disAsmFile != jitstdout()) { fclose(disAsmFile); } diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index bcf7c7be401c21..57c52855ea8393 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -31,8 +31,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /*****************************************************************************/ -FILE* jitstdout = nullptr; - ICorJitHost* g_jitHost = nullptr; bool g_jitInitialized = false; @@ -72,15 +70,28 @@ extern "C" DLLEXPORT void jitStartup(ICorJitHost* jitHost) assert(!JitConfig.isInitialized()); JitConfig.initialize(jitHost); +#ifdef FEATURE_TRACELOGGING + JitTelemetry::NotifyDllProcessAttach(); +#endif + Compiler::compStartup(); + + g_jitInitialized = true; +} + +static FILE* volatile s_jitstdout; + +static FILE* jitstdoutInit() +{ const WCHAR* jitStdOutFile = JitConfig.JitStdOutFile(); + FILE* file = nullptr; if (jitStdOutFile != nullptr) { - jitstdout = _wfopen(jitStdOutFile, W("a")); - assert(jitstdout != nullptr); + file = _wfopen(jitStdOutFile, W("a")); + assert(file != nullptr); } #if !defined(HOST_UNIX) - if (jitstdout == nullptr) + if (file == nullptr) { int stdoutFd = _fileno(procstdout()); // Check fileno error output(s) -1 may overlap with errno result @@ -89,46 +100,61 @@ extern "C" DLLEXPORT void jitStartup(ICorJitHost* jitHost) // or bogus and avoid making further calls. if ((stdoutFd != -1) && (stdoutFd != -2) && (errno != EINVAL)) { - int jitstdoutFd = _dup(_fileno(procstdout())); + int jitstdoutFd = _dup(stdoutFd); // Check the error status returned by dup. if (jitstdoutFd != -1) { _setmode(jitstdoutFd, _O_TEXT); - jitstdout = _fdopen(jitstdoutFd, "w"); - assert(jitstdout != nullptr); + file = _fdopen(jitstdoutFd, "w"); + assert(file != nullptr); // Prevent the FILE* from buffering its output in order to avoid calls to // `fflush()` throughout the code. - setvbuf(jitstdout, nullptr, _IONBF, 0); + setvbuf(file, nullptr, _IONBF, 0); } } } #endif // !HOST_UNIX - // If jitstdout is still null, fallback to whatever procstdout() was - // initially set to. - if (jitstdout == nullptr) + if (file == nullptr) { - jitstdout = procstdout(); + file = procstdout(); } -#ifdef FEATURE_TRACELOGGING - JitTelemetry::NotifyDllProcessAttach(); -#endif - Compiler::compStartup(); + FILE* observed = InterlockedCompareExchangeT(&s_jitstdout, file, nullptr); - g_jitInitialized = true; + if (observed != nullptr) + { + if (file != procstdout()) + { + fclose(file); + } + + return observed; + } + + return file; } -#ifndef DEBUG +FILE* jitstdout() +{ + FILE* file = s_jitstdout; + if (file != nullptr) + { + return file; + } + + return jitstdoutInit(); +} + +// Like printf/logf, but only outputs to jitstdout -- skips call back into EE. void jitprintf(const char* fmt, ...) { va_list vl; va_start(vl, fmt); - vfprintf(jitstdout, fmt, vl); + vfprintf(jitstdout(), fmt, vl); va_end(vl); } -#endif void jitShutdown(bool processIsTerminating) { @@ -139,14 +165,15 @@ void jitShutdown(bool processIsTerminating) Compiler::compShutdown(); - if (jitstdout != procstdout()) + FILE* file = s_jitstdout; + if ((file != nullptr) && (file != procstdout())) { // When the process is terminating, the fclose call is unnecessary and is also prone to // crashing since the UCRT itself often frees the backing memory earlier on in the // termination sequence. if (!processIsTerminating) { - fclose(jitstdout); + fclose(file); } } diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index c85724f9240b98..8a671b7a757b88 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -215,7 +215,7 @@ unsigned emitter::emitInt32CnsCnt; unsigned emitter::emitNegCnsCnt; unsigned emitter::emitPow2CnsCnt; -void emitterStaticStats(FILE* fout) +void emitterStaticStats() { // The IG buffer size depends on whether we are storing a debug info pointer or not. For our purposes // here, do not include that. @@ -227,6 +227,8 @@ void emitterStaticStats(FILE* fout) insGroup* igDummy = nullptr; + FILE* fout = jitstdout(); + fprintf(fout, "\n"); fprintf(fout, "insGroup:\n"); fprintf(fout, "Offset / size of igNext = %3zu / %2zu\n", offsetof(insGroup, igNext), diff --git a/src/coreclr/jit/error.cpp b/src/coreclr/jit/error.cpp index 01e6f734b89f89..06635f5d582a1d 100644 --- a/src/coreclr/jit/error.cpp +++ b/src/coreclr/jit/error.cpp @@ -387,7 +387,7 @@ int logf(const char* fmt, ...) { // if the EE refuses to log it, we try to send it to stdout va_start(args, fmt); - written = vflogf(jitstdout, fmt, args); + written = vflogf(jitstdout(), fmt, args); va_end(args); } #if 0 // Enable this only when you need it @@ -448,7 +448,7 @@ void gcDump_logf(const char* fmt, ...) { // if the EE refuses to log it, we try to send it to stdout va_start(args, fmt); - vflogf(jitstdout, fmt, args); + vflogf(jitstdout(), fmt, args); va_end(args); } #if 0 // Enable this only when you need it diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index e79bdb0e46368a..6dbc5e9a654845 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -674,7 +674,7 @@ FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, PhasePositi } else if (strcmp(filename, "stdout") == 0) { - fgxFile = jitstdout; + fgxFile = jitstdout(); *wbDontClose = true; } else if (strcmp(filename, "stderr") == 0) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index d02ce4714d8a2e..a30c3794efdd29 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -481,10 +481,12 @@ void GenTree::ReportOperBashing(FILE* f) #if MEASURE_NODE_SIZE -void GenTree::DumpNodeSizes(FILE* fp) +void GenTree::DumpNodeSizes() { // Dump the sizes of the various GenTree flavors + FILE* fp = jitstdout(); + fprintf(fp, "Small tree node size = %zu bytes\n", TREE_NODE_SZ_SMALL); fprintf(fp, "Large tree node size = %zu bytes\n", TREE_NODE_SZ_LARGE); fprintf(fp, "\n"); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 27688c3d41790d..109da6a15c30d8 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2311,7 +2311,7 @@ struct GenTree void SetIndirExceptionFlags(Compiler* comp); #if MEASURE_NODE_SIZE - static void DumpNodeSizes(FILE* fp); + static void DumpNodeSizes(); #endif #ifdef DEBUG diff --git a/src/coreclr/jit/host.h b/src/coreclr/jit/host.h index c99a0601e499b0..0ccefae924e637 100644 --- a/src/coreclr/jit/host.h +++ b/src/coreclr/jit/host.h @@ -3,6 +3,8 @@ /*****************************************************************************/ +void jitprintf(const char* fmt, ...); + #ifdef DEBUG #undef printf @@ -44,7 +46,6 @@ extern "C" void ANALYZER_NORETURN __cdecl assertAbort(const char* why, const cha // Re-define printf in Release to use jitstdout (can be overwritten with DOTNET_JitStdOutFile=file) #undef printf #define printf jitprintf -void jitprintf(const char* fmt, ...); #undef assert #define assert(p) (void)0 @@ -55,7 +56,7 @@ void jitprintf(const char* fmt, ...); #define _HOST_H_ /*****************************************************************************/ -extern FILE* jitstdout; +FILE* jitstdout(); inline FILE* procstdout() { diff --git a/src/coreclr/jit/inline.cpp b/src/coreclr/jit/inline.cpp index bae5755707594d..0ded3ef3482a70 100644 --- a/src/coreclr/jit/inline.cpp +++ b/src/coreclr/jit/inline.cpp @@ -480,7 +480,7 @@ void InlineContext::DumpData(unsigned indent) { const char* inlineReason = InlGetObservationString(m_Observation); printf("%*s%u,\"%s\",\"%s\",", indent, "", GetOrdinal(), inlineReason, calleeName); - m_Policy->DumpData(jitstdout); + m_Policy->DumpData(jitstdout()); printf("\n"); } diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 5c8fe4aae77889..0a33ba3faba9bd 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -1421,7 +1421,7 @@ PhaseStatus LinearScan::doLinearScan() #endif ) { - dumpLsraStats(jitstdout); + dumpLsraStats(jitstdout()); } #endif // TRACK_LSRA_STATS From bf1e333ef05ce1977cca4f6502f020d19e214e7d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:31:42 -0700 Subject: [PATCH 267/345] [release/8.0] Check if loop body occured before loopTop and if so unmark alignment (#91918) * Check if loop body occured before loopTop" * Check if bbNatLoopNum is not NOT_IN_LOOP * review feedback --------- Co-authored-by: Kunal Pathak --- src/coreclr/jit/compiler.cpp | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 033e0990070d23..37534460a6c5c8 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5280,6 +5280,13 @@ PhaseStatus Compiler::placeLoopAlignInstructions() weight_t minBlockSoFar = BB_MAX_WEIGHT; BasicBlock* bbHavingAlign = nullptr; BasicBlock::loopNumber currentAlignedLoopNum = BasicBlock::NOT_IN_LOOP; + bool visitedLoopNum[BasicBlock::MAX_LOOP_NUM]; + memset(visitedLoopNum, false, sizeof(visitedLoopNum)); + +#ifdef DEBUG + unsigned visitedBlockForLoopNum[BasicBlock::MAX_LOOP_NUM]; + memset(visitedBlockForLoopNum, 0, sizeof(visitedBlockForLoopNum)); +#endif if ((fgFirstBB != nullptr) && fgFirstBB->isLoopAlign()) { @@ -5302,7 +5309,7 @@ PhaseStatus Compiler::placeLoopAlignInstructions() } } - // If there is a unconditional jump (which is not part of callf/always pair) + // If there is an unconditional jump (which is not part of callf/always pair) if (opts.compJitHideAlignBehindJmp && (block->bbJumpKind == BBJ_ALWAYS) && !block->isBBCallAlwaysPairTail()) { // Track the lower weight blocks @@ -5356,12 +5363,19 @@ PhaseStatus Compiler::placeLoopAlignInstructions() madeChanges = true; unmarkedLoopAlign = true; } - else if ((block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) && (block->bbNatLoopNum == loopTop->bbNatLoopNum)) + else if ((loopTop->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) && visitedLoopNum[loopTop->bbNatLoopNum]) { +#ifdef DEBUG + char buffer[100]; + sprintf_s(buffer, 100, "loop block " FMT_BB " appears before top of loop", + visitedBlockForLoopNum[loopTop->bbNatLoopNum]); +#endif + // In some odd cases we may see blocks within the loop before we see the // top block of the loop. Just bail on aligning such loops. // - loopTop->unmarkLoopAlign(this DEBUG_ARG("loop block appears before top of loop")); + + loopTop->unmarkLoopAlign(this DEBUG_ARG(buffer)); madeChanges = true; unmarkedLoopAlign = true; } @@ -5396,6 +5410,20 @@ PhaseStatus Compiler::placeLoopAlignInstructions() break; } } + + if (block->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { +#ifdef DEBUG + if (!visitedLoopNum[block->bbNatLoopNum]) + { + // Record the first block for which bbNatLoopNum was seen for + // debugging purpose. + visitedBlockForLoopNum[block->bbNatLoopNum] = block->bbNum; + } +#endif + // If this block is part of loop, mark the loopNum as visited. + visitedLoopNum[block->bbNatLoopNum] = true; + } } assert(loopsToProcess == 0); From 644856c110bb27dcc8fad8664f7886393972aebd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:43:24 -0700 Subject: [PATCH 268/345] [release/8.0] Fix wasi build. (#92232) * Fix wasi build. * dummy change in wasi README to trigger a build * dummy change in wasi to trigger a build --------- Co-authored-by: Zoltan Varga Co-authored-by: Ankit Jain --- eng/pipelines/common/templates/pipeline-with-resources.yml | 4 ++-- src/mono/wasi/README.md | 3 ++- src/mono/wasi/build/WasiApp.targets | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index c30ce8597808d8..02242394fba671 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -85,12 +85,12 @@ resources: image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8 - container: browser_wasm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly-20230913040940-1edc1c6 env: ROOTFS_DIR: /crossrootfs/x64 - container: wasi_wasm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly-20230913040940-1edc1c6 env: ROOTFS_DIR: /crossrootfs/x64 diff --git a/src/mono/wasi/README.md b/src/mono/wasi/README.md index 66e59384297bb3..4c8759006359da 100644 --- a/src/mono/wasi/README.md +++ b/src/mono/wasi/README.md @@ -17,6 +17,7 @@ or for just native rebuild ./build.sh -bl -os wasi -subset mono.runtime+libs.native+mono.wasiruntime -c Debug ``` + ### 3. Run it Finally, you can build and run the sample: @@ -49,4 +50,4 @@ Download the Mono Debug extension and configure a launch.json like this: } ] } -``` \ No newline at end of file +``` diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index 1b8fc4e3fa9333..099ba8c3ebea27 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -4,8 +4,6 @@ + Provides the System.MathF for .NET Standard 2.0 + + true + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md index 5ce176a315dedb..b19975c09f41f4 100644 --- a/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md +++ b/src/libraries/Microsoft.Bcl.Numerics/src/PACKAGE.md @@ -10,8 +10,6 @@ As of .NET Core 2.0 and .NET Standard 2.1, the C# language has support for math ## How to Use - - ```C# using System; diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs b/src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs new file mode 100644 index 00000000000000..128a3174ad0c4e --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/src/System/MathF.cs @@ -0,0 +1,332 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/*============================================================ +** +** Purpose: Some single-precision floating-point math operations +** +===========================================================*/ + +//This class contains only static members and doesn't require serialization. + +//For most of this implementation for .NET Framework we just defer to System.Math and do a cast internally from single to double. +//We do this because it safer and less likely to break people since that is what they are alrady doing. Also, adding in the +//extra pinvokes needed to not do this route would probably incur an extra overhead that would be undersired. + +//For any version of .NET Core this just forwards directly to the MathF implementation inside the runtime. + +//There are a few cases where .NET Framework handles things differently than .NET Core does. For example, it returns -0 and +0 +//when using things like Min/Max, and they count as different values from each other. This is fixed in .NET Core, but since its +//inherent in .NET Framework we decided to leave that behavior as is for this BCL. + +using System.Diagnostics.Contracts; + +namespace System +{ + /// + /// Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions. + /// + public static class MathF + { + /// + /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, p. + /// + public const float PI = 3.14159265f; + + /// + /// Represents the natural logarithmic base, specified by the constant, e. + /// + public const float E = 2.71828183f; + + private static float NegativeZero = Int32BitsToSingle(unchecked((int)0x80000000)); + + private static unsafe float Int32BitsToSingle(int value) + { + return *((float*)&value); + } + + [Pure] + private static unsafe bool IsNegative(float f) + { + return (*(uint*)(&f) & 0x80000000) == 0x80000000; + } + + /// + /// Returns the absolute value of a single-precision floating-point number. + /// + /// The number to take the absolute value of. + /// The absolute value of + public static float Abs(float x) => Math.Abs(x); + + /// + /// Returns the angle whose cosine is the specified number. + /// + /// The number to take the acos of. + /// The acos of + public static float Acos(float x) => (float)Math.Acos(x); + + /// + /// Returns the angle whose sine is the specified number. + /// + /// The number to take the asin of. + /// The asin of + public static float Asin(float x) => (float)Math.Asin(x); + + /// + /// Returns the angle whose tangent is the specified number. + /// + /// The number to take the atan of. + /// The atan of + public static float Atan(float x) => (float)Math.Atan(x); + + /// + /// Returns the angle whose tangent is the quotient of two specified numbers. + /// + /// The first number. + /// The second number. + /// The angle whose tangent is the quotient of and + public static float Atan2(float y, float x) => (float)Math.Atan2(y, x); + + /// + /// Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number. + /// + /// The number to take the ceiling of. + /// The ceiling of + public static float Ceiling(float x) => (float)Math.Ceiling(x); + + /// + /// Returns the cosine of the specified angle. + /// + /// The angle to take the cosine of. + /// The cosine of + public static float Cos(float x) => (float)Math.Cos(x); + + /// + /// Returns the hyperbolic cosine of the specified angle. + /// + /// The angle to take the hyperbolic cosine of. + /// The hyperbolic cosine of + public static float Cosh(float x) => (float)Math.Cosh(x); + + /// + /// Returns e raised to the specified power. + /// + /// The number to raise e to. + /// e raised to the power of + public static float Exp(float x) => (float)Math.Exp(x); + + /// + /// Returns the largest integral value less than or equal to the specified single-precision floating-point number. + /// + /// The number to take the floor of. + /// The floor of + public static float Floor(float x) => (float)Math.Floor(x); + + /// + /// Returns the remainder resulting from the division of a specified number by another specified number. + /// + /// The numerator + /// The denominator + /// The result of dividing by + public static float IEEERemainder(float x, float y) + { + if (float.IsNaN(x)) + { + return x; // IEEE 754-2008: NaN payload must be preserved + } + + if (float.IsNaN(y)) + { + return y; // IEEE 754-2008: NaN payload must be preserved + } + + var regularMod = x % y; + + if (float.IsNaN(regularMod)) + { + return float.NaN; + } + + if ((regularMod == 0) && IsNegative(x)) + { + return NegativeZero; + } + + var alternativeResult = (regularMod - (Abs(y) * Sign(x))); + + if (Abs(alternativeResult) == Abs(regularMod)) + { + var divisionResult = x / y; + var roundedResult = Round(divisionResult); + + if (Abs(roundedResult) > Abs(divisionResult)) + { + return alternativeResult; + } + else + { + return regularMod; + } + } + + if (Abs(alternativeResult) < Abs(regularMod)) + { + return alternativeResult; + } + else + { + return regularMod; + } + } + + /// + /// Returns the natural (base e) logarithm of a specified number. + /// + /// The number to take the natural log of. + /// The natural log of + public static float Log(float x) => (float)Math.Log(x); + + /// + /// Returns the logarithm of a specified number in a specified base. + /// + /// The number to take the log of. + /// The base of the log + /// The log of with base + public static float Log(float x, float y) + { + if (float.IsNaN(x)) + { + return x; // IEEE 754-2008: NaN payload must be preserved + } + + if (float.IsNaN(y)) + { + return y; // IEEE 754-2008: NaN payload must be preserved + } + + if (y == 1) + { + return float.NaN; + } + + if ((x != 1) && ((y == 0) || float.IsPositiveInfinity(y))) + { + return float.NaN; + } + + return Log(x) / Log(y); + } + + /// + /// Returns the base 10 logarithm of a specified number. + /// + /// The number to take the base 10 log of. + /// The base 10 log of + public static float Log10(float x) => (float)Math.Log10(x); + + /// + /// Returns the larger of two single-precision floating-point numbers. + /// + /// The first number to compare. + /// The second number to compare. + /// The larger of and + public static float Max(float x, float y) => Math.Max(x, y); + + /// + /// Returns the smaller of two single-precision floating-point numbers. + /// + /// The first number to compare. + /// The second number to compare. + /// The smaller of and + public static float Min(float x, float y) => Math.Min(x, y); + + /// + /// Returns a specified number raised to the specified power. + /// + /// The base number. + /// The specified power. + /// raised to the power of + public static float Pow(float x, float y) => (float)Math.Pow(x, y); + + /// + /// Rounds a single-precision floating-point value to the nearest integral value, and rounds midpoint values to the nearest even number. + /// + /// The number to round. + /// The rounded representation of + public static float Round(float x) => (float)Math.Round(x); + + /// + /// Rounds a single-precision floating-point value to a specified number of fractional digits, and rounds midpoint values to the nearest even number. + /// + /// The number to round. + /// How many fractional digits to keep. + /// The rounded representation of with fractional digits + public static float Round(float x, int digits) => (float)Math.Round(x, digits); + + /// + /// Rounds a single-precision floating-point value to a specified number of fractional digits using the specified rounding convention. + /// + /// The number to round. + /// How many fractional digits to keep. + /// The rounding convention to use. + /// The rounded representation of with fractional digits using rounding convention + public static float Round(float x, int digits, MidpointRounding mode) => (float)Math.Round(x, digits, mode); + + /// + /// Rounds a single-precision floating-point value to an integer using the specified rounding convention. + /// + /// The number to round. + /// The rounding convention to use. + /// The rounded representation of using rounding convention + public static float Round(float x, MidpointRounding mode) => (float)Math.Round(x, mode); + + /// + /// Returns an integer that indicates the sign of a single-precision floating-point number. + /// + /// The number check the sign of. + /// The sign of + public static int Sign(float x) => Math.Sign(x); + + /// + /// Returns the sine of the specified angle. + /// + /// The angle to take the sine of. + /// The sine of + public static float Sin(float x) => (float)Math.Sin(x); + + /// + /// Returns the hyperbolic sine of the specified angle. + /// + /// The angle to take the hyperbolic sine of. + /// The hyperbolic sine of + public static float Sinh(float x) => (float)Math.Sinh(x); + + /// + /// Returns the square root of a specified number. + /// + /// The number to take the square root of. + /// The square root of + public static float Sqrt(float x) => (float)Math.Sqrt(x); + + /// + /// Returns the tangent of the specified angle. + /// + /// The angle to take the tangent of. + /// The tangent of + public static float Tan(float x) => (float)Math.Tan(x); + + /// + /// Returns the hyperbolic tangent of the specified angle. + /// + /// The angle to take the hyperbolic tangent of. + /// The hyperbolic tangent of + public static float Tanh(float x) => (float)Math.Tanh(x); + + /// + /// Calculates the integral part of a specified single-precision floating-point number. + /// + /// The number to truncate. + /// The truncated representation of + public static float Truncate(float x) => (float)Math.Truncate(x); + } +} diff --git a/src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs b/src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs new file mode 100644 index 00000000000000..641ce5525675f4 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/src/System/Microsoft.Bcl.Numerics.Forwards.cs @@ -0,0 +1,4 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.MathF))] diff --git a/src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs b/src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs new file mode 100644 index 00000000000000..3aa148a2161564 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/tests/MathF.cs @@ -0,0 +1,1169 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +#pragma warning disable xUnit1025 // reporting duplicate test cases due to not distinguishing 0.0 from -0.0 + +namespace System.Tests +{ + public static class MathFTests + { + // binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this + // is slightly too accurate when writing tests meant to run against libm implementations + // for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. + // + // The tests themselves will take CrossPlatformMachineEpsilon and adjust it according to the expected result + // so that the delta used for comparison will compare the most significant digits and ignore + // any digits that are outside the single precision range (6-9 digits). + + // For example, a test with an expect result in the format of 0.xxxxxxxxx will use + // CrossPlatformMachineEpsilon for the variance, while an expected result in the format of 0.0xxxxxxxxx + // will use CrossPlatformMachineEpsilon / 10 and expected result in the format of x.xxxxxx will + // use CrossPlatformMachineEpsilon * 10. + private const float CrossPlatformMachineEpsilon = 4.76837158e-07f; + + // The existing estimate functions either have an error of no more than 1.5 * 2^-12 (approx. 3.66e-04) + // or perform one Newton-Raphson iteration which, for the currently tested values, gives an error of + // no more than approx. 1.5 * 2^-7 (approx 1.17e-02). + private const double CrossPlatformMachineEpsilonForEstimates = 1.171875e-02f; + + [Fact] + public static void E() + { + Assert.Equal(2.71828183f, MathF.E); + } + + [Fact] + public static void Pi() + { + Assert.Equal(3.14159265f, MathF.PI); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-3.14159265f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // value: -(pi) expected: (pi) + [InlineData(-2.71828183f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // value: -(e) expected: (e) + [InlineData(-2.30258509f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10)) expected: (ln(10)) + [InlineData(-1.57079633f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) expected: (pi / 2) + [InlineData(-1.44269504f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e)) expected: (log2(e)) + [InlineData(-1.41421356f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2)) expected: (sqrt(2)) + [InlineData(-1.12837917f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi)) expected: (2 / sqrt(pi)) + [InlineData(-1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, 0.785398163f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) expected: (pi / 4) + [InlineData(-0.707106781f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) expected: (1 / sqrt(2)) + [InlineData(-0.693147181f, 0.693147181f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) expected: (ln(2)) + [InlineData(-0.636619772f, 0.636619772f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) expected: (2 / pi) + [InlineData(-0.434294482f, 0.434294482f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) expected: (log10(e)) + [InlineData(-0.318309886f, 0.318309886f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) expected: (1 / pi) + [InlineData(-0.0f, 0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.318309886f, CrossPlatformMachineEpsilon)] // value: (1 / pi) expected: (1 / pi) + [InlineData(0.434294482f, 0.434294482f, CrossPlatformMachineEpsilon)] // value: (log10(e)) expected: (log10(e)) + [InlineData(0.636619772f, 0.636619772f, CrossPlatformMachineEpsilon)] // value: (2 / pi) expected: (2 / pi) + [InlineData(0.693147181f, 0.693147181f, CrossPlatformMachineEpsilon)] // value: (ln(2)) expected: (ln(2)) + [InlineData(0.707106781f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) expected: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.785398163f, CrossPlatformMachineEpsilon)] // value: (pi / 4) expected: (pi / 4) + [InlineData(1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) expected: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) expected: (sqrt(2)) + [InlineData(1.44269504f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) expected: (log2(e)) + [InlineData(1.57079633f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) expected: (pi / 2) + [InlineData(2.30258509f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) expected: (ln(10)) + [InlineData(2.71828183f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // value: (e) expected: (e) + [InlineData(3.14159265f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // value: (pi) expected: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Abs(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Abs(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(-0.911733915f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(-0.668201510f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(-0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(0.127751218f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(0.155943695f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(0.428125148f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(0.540302306f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.707106781f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4), value: (1 / sqrt(2)) + [InlineData(0.760244597f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(0.769238901f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.804109828f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.907167129f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.949765715f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2)) + [InlineData(2.71828183f, float.NaN, 0.0f)] // value: (e) + [InlineData(3.14159265f, float.NaN, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Acos(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Acos(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-0.991806244f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(-0.987765946f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(-0.903719457f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(-0.841470985f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.743980337f, -0.839007561f, CrossPlatformMachineEpsilon)] // expected: -(pi - ln(10)) + [InlineData(-0.707106781f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4), value: (1 / sqrt(2)) + [InlineData(-0.649636939f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(-0.638961276f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(-0.594480769f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(-0.420770483f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(-0.410781291f, -0.423310825f, CrossPlatformMachineEpsilon)] // expected: -(pi - e) + [InlineData(-0.312961796f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.312961796f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(0.410781291f, 0.423310825f, CrossPlatformMachineEpsilon)] // expected: (pi - e) + [InlineData(0.420770483f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.594480769f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.638961276f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.649636939f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(0.707106781f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4), value: (1 / sqrt(2)) + [InlineData(0.743980337f, 0.839007561f, CrossPlatformMachineEpsilon)] // expected: (pi - ln(10)) + [InlineData(0.841470985f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.903719457f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(0.987765946f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(0.991806244f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2)) + [InlineData(2.71828183f, float.NaN, 0.0f)] // value: (e) + [InlineData(3.14159265f, float.NaN, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Asin(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Asin(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-7.76357567f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(-6.33411917f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(-2.11087684f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(-1.55740772f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.11340715f, -0.839007561f, CrossPlatformMachineEpsilon)] // expected: -(pi - ln(10)) + [InlineData(-1.0f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(-0.854510432f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(-0.830640878f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(-0.739302950f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(-0.463829067f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(-0.450549534f, -0.423310825f, CrossPlatformMachineEpsilon)] // expected: -(pi - e) + [InlineData(-0.329514733f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.329514733f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(0.450549534f, 0.423310825f, CrossPlatformMachineEpsilon)] // expected: (pi - e) + [InlineData(0.463829067f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.739302950f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.830640878f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.854510432f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(1.0f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(1.11340715f, 0.839007561f, CrossPlatformMachineEpsilon)] // expected: (pi - ln(10)) + [InlineData(1.55740772f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(2.11087684f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(6.33411917f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(7.76357567f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(float.PositiveInfinity, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + public static void Atan(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Atan(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, -1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(float.NegativeInfinity, -0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(float.NegativeInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NegativeInfinity, 0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(float.NegativeInfinity, 1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-1.0f, -1.0f, -2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: -(3 * pi / 4) + [InlineData(-1.0f, -0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-1.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-1.0f, 0.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(-1.0f, 1.0f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(-1.0f, float.PositiveInfinity, -0.0f, 0.0f)] + [InlineData(-0.991806244f, -0.127751218f, -1.69889761f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - log2(e)) + [InlineData(-0.991806244f, 0.127751218f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(-0.987765946f, -0.155943695f, -1.72737909f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - sqrt(2)) + [InlineData(-0.987765946f, 0.155943695f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(-0.903719457f, -0.428125148f, -2.01321349f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (2 / sqrt(pi)) + [InlineData(-0.903719457f, 0.428125148f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi) + [InlineData(-0.841470985f, -0.540302306f, -2.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - 1) + [InlineData(-0.841470985f, 0.540302306f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.743980337f, -0.668201510f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) + [InlineData(-0.743980337f, 0.668201510f, -0.839007561f, CrossPlatformMachineEpsilon)] // expected: -(pi - ln(10)) + [InlineData(-0.707106781f, -0.707106781f, -2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: -(3 * pi / 4), y: -(1 / sqrt(2)) x: -(1 / sqrt(2)) + [InlineData(-0.707106781f, 0.707106781f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4), y: -(1 / sqrt(2)) x: (1 / sqrt(2)) + [InlineData(-0.649636939f, -0.760244597f, -2.43448587f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (1 / sqrt(2)) + [InlineData(-0.649636939f, 0.760244597f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(-0.638961276f, -0.769238901f, -2.44844547f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - ln(2)) + [InlineData(-0.638961276f, 0.769238901f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(-0.594480769f, -0.804109828f, -2.50497288f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (2 / pi)) + [InlineData(-0.594480769f, 0.804109828f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(-0.420770483f, -0.907167129f, -2.70729817f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - log10(e)) + [InlineData(-0.420770483f, 0.907167129f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(-0.410781291f, -0.911733915f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) + [InlineData(-0.410781291f, 0.911733915f, -0.423310825f, CrossPlatformMachineEpsilon)] // expected: -(pi - e) + [InlineData(-0.312961796f, -0.949765715f, -2.82328277f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi - (1 / pi)) + [InlineData(-0.312961796f, 0.949765715f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(-0.0f, float.NegativeInfinity, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(-0.0f, -1.0f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(-0.0f, -0.0f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(-0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-0.0f, 0.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, 1.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, float.PositiveInfinity, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(float.NaN, -1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, -0.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NaN, 0.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, 1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(0.0f, -1.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(0.0f, -0.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f, 0.0f)] + [InlineData(0.0f, 1.0f, 0.0f, 0.0f)] + [InlineData(0.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(0.312961796f, -0.949765715f, 2.82328277f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (1 / pi)) + [InlineData(0.312961796f, 0.949765715f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(0.410781291f, -0.911733915f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(0.410781291f, 0.911733915f, 0.423310825f, CrossPlatformMachineEpsilon)] // expected: (pi - e) + [InlineData(0.420770483f, -0.907167129f, 2.70729817f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - log10(e)) + [InlineData(0.420770483f, 0.907167129f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(0.594480769f, -0.804109828f, 2.50497288f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (2 / pi)) + [InlineData(0.594480769f, 0.804109828f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(0.638961276f, -0.769238901f, 2.44844547f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - ln(2)) + [InlineData(0.638961276f, 0.769238901f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(0.649636939f, -0.760244597f, 2.43448587f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (1 / sqrt(2)) + [InlineData(0.649636939f, 0.760244597f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(0.707106781f, -0.707106781f, 2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: (3 * pi / 4), y: (1 / sqrt(2)) x: -(1 / sqrt(2)) + [InlineData(0.707106781f, 0.707106781f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4), y: (1 / sqrt(2)) x: (1 / sqrt(2)) + [InlineData(0.743980337f, -0.668201510f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(0.743980337f, 0.668201510f, 0.839007561f, CrossPlatformMachineEpsilon)] // expected: (pi - ln(10)) + [InlineData(0.841470985f, -0.540302306f, 2.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - 1) + [InlineData(0.841470985f, 0.540302306f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.903719457f, -0.428125148f, 2.01321349f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - (2 / sqrt(pi)) + [InlineData(0.903719457f, 0.428125148f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(0.987765946f, -0.155943695f, 1.72737909f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - sqrt(2)) + [InlineData(0.987765946f, 0.155943695f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(0.991806244f, -0.127751218f, 1.69889761f, CrossPlatformMachineEpsilon * 10)] // expected: (pi - log2(e)) + [InlineData(0.991806244f, 0.127751218f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(1.0f, -1.0f, 2.35619449f, CrossPlatformMachineEpsilon * 10)] // expected: (3 * pi / 4) + [InlineData(1.0f, -0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(1.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(1.0f, 0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(1.0f, 1.0f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(1.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, -1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.PositiveInfinity, -0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.PositiveInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.PositiveInfinity, 0.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(float.PositiveInfinity, 1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + public static void Atan2(float y, float x, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Atan2(y, x), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)] + [InlineData(-3.14159265f, -3.0f, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, -2.0f, 0.0f)] // value: -(e) + [InlineData(-2.30258509f, -2.0f, 0.0f)] // value: -(ln(10)) + [InlineData(-1.57079633f, -1.0f, 0.0f)] // value: -(pi / 2) + [InlineData(-1.44269504f, -1.0f, 0.0f)] // value: -(log2(e)) + [InlineData(-1.41421356f, -1.0f, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -1.0f, 0.0f)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.0f, 0.0f)] +#if NETFRAMEWORK + [InlineData(-0.785398163f, 0.0f, 0.0f)] // value: (pi / 4) + [InlineData(-0.707106781f, 0.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, 0.0f, 0.0f)] // value: (ln(2)) + [InlineData(-0.636619772f, 0.0f, 0.0f)] // value: (2 / pi) + [InlineData(-0.434294482f, 0.0f, 0.0f)] // value: (log10(e)) + [InlineData(-0.318309886f, 0.0f, 0.0f)] // value: (1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] +#else + [InlineData(-0.785398163f, -0.0f, 0.0f)] // value: (pi / 4) + [InlineData(-0.707106781f, -0.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, -0.0f, 0.0f)] // value: (ln(2)) + [InlineData(-0.636619772f, -0.0f, 0.0f)] // value: (2 / pi) + [InlineData(-0.434294482f, -0.0f, 0.0f)] // value: (log10(e)) + [InlineData(-0.318309886f, -0.0f, 0.0f)] // value: (1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] +#endif + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 1.0f, 0.0f)] // value: (1 / pi) + [InlineData(0.434294482f, 1.0f, 0.0f)] // value: (log10(e)) + [InlineData(0.636619772f, 1.0f, 0.0f)] // value: (2 / pi) + [InlineData(0.693147181f, 1.0f, 0.0f)] // value: (ln(2)) + [InlineData(0.707106781f, 1.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 1.0f, 0.0f)] // value: (pi / 4) + [InlineData(1.0f, 1.0f, 0.0f)] + [InlineData(1.12837917f, 2.0f, 0.0f)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 2.0f, 0.0f)] // value: (sqrt(2)) + [InlineData(1.44269504f, 2.0f, 0.0f)] // value: (log2(e)) + [InlineData(1.57079633f, 2.0f, 0.0f)] // value: (pi / 2) + [InlineData(2.30258509f, 3.0f, 0.0f)] // value: (ln(10)) + [InlineData(2.71828183f, 3.0f, 0.0f)] // value: (e) + [InlineData(3.14159265f, 4.0f, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Ceiling(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Ceiling(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi) + [InlineData(-2.71828183f, -0.911733918f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, -0.668201510f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, 0.0f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) + [InlineData(-1.44269504f, 0.127751218f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, 0.155943695f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, 0.428125148f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, 0.540302306f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: (1 / sqrt(2)) + [InlineData(-0.707106781f, 0.760244597f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, 0.769238901f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, 0.804109828f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, 0.907167129f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, 0.949765715f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.318309886f, 0.949765715f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.907167129f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.804109828f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.769238901f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.760244597f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) + [InlineData(1.0f, 0.540302306f, CrossPlatformMachineEpsilon)] + [InlineData(1.12837917f, 0.428125148f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 0.155943695f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, 0.127751218f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.57079633f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.30258509f, -0.668201510f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.71828183f, -0.911733918f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Cos(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Cos(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-3.14159265f, 11.5919533f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(-2.71828183f, 7.61012514f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(-2.30258509f, 5.05f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(-1.57079633f, 2.50917848f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(-1.44269504f, 2.23418810f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(-1.41421356f, 2.17818356f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(-1.12837917f, 1.70710014f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(-1.0f, 1.54308063f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, 1.32460909f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(-0.707106781f, 1.26059184f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, 1.25f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(-0.636619772f, 1.20957949f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(-0.434294482f, 1.09579746f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(-0.318309886f, 1.05108979f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.318309886f, 1.05108979f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(0.434294482f, 1.09579746f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(0.636619772f, 1.20957949f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(0.693147181f, 1.25f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(0.707106781f, 1.26059184f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 1.32460909f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(1.0f, 1.54308063f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.70710014f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 2.17818356f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 2.23418810f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 2.50917848f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 5.05f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, 7.61012514f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.14159265f, 11.5919533f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Cosh(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Cosh(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, 0.0f, CrossPlatformMachineEpsilon)] + [InlineData(-3.14159265f, 0.0432139183f, CrossPlatformMachineEpsilon / 10)] // value: -(pi) + [InlineData(-2.71828183f, 0.0659880358f, CrossPlatformMachineEpsilon / 10)] // value: -(e) + [InlineData(-2.30258509f, 0.1f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, 0.207879576f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) + [InlineData(-1.44269504f, 0.236290088f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, 0.243116734f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, 0.323557264f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, 0.367879441f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, 0.455938128f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) + [InlineData(-0.707106781f, 0.493068691f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, 0.5f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, 0.529077808f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, 0.647721485f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, 0.727377349f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.318309886f, 1.37480223f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) + [InlineData(0.434294482f, 1.54387344f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) + [InlineData(0.636619772f, 1.89008116f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) + [InlineData(0.693147181f, 2.0f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) + [InlineData(0.707106781f, 2.02811498f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 2.19328005f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(1.0f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(1.12837917f, 3.09064302f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 4.11325038f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 4.23208611f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 4.81047738f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 10.0f, CrossPlatformMachineEpsilon * 100)] // value: (ln(10)) + [InlineData(2.71828183f, 15.1542622f, CrossPlatformMachineEpsilon * 100)] // value: (e) + [InlineData(3.14159265f, 23.1406926f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Exp(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Exp(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)] + [InlineData(-3.14159265f, -4.0f, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, -3.0f, 0.0f)] // value: -(e) + [InlineData(-2.30258509f, -3.0f, 0.0f)] // value: -(ln(10)) + [InlineData(-1.57079633f, -2.0f, 0.0f)] // value: -(pi / 2) + [InlineData(-1.44269504f, -2.0f, 0.0f)] // value: -(log2(e)) + [InlineData(-1.41421356f, -2.0f, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -2.0f, 0.0f)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.0f, 0.0f)] + [InlineData(-0.785398163f, -1.0f, 0.0f)] // value: -(pi / 4) + [InlineData(-0.707106781f, -1.0f, 0.0f)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -1.0f, 0.0f)] // value: -(ln(2)) + [InlineData(-0.636619772f, -1.0f, 0.0f)] // value: -(2 / pi) + [InlineData(-0.434294482f, -1.0f, 0.0f)] // value: -(log10(e)) + [InlineData(-0.318309886f, -1.0f, 0.0f)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.0f, 0.0f)] // value: (1 / pi) + [InlineData(0.434294482f, 0.0f, 0.0f)] // value: (log10(e)) + [InlineData(0.636619772f, 0.0f, 0.0f)] // value: (2 / pi) + [InlineData(0.693147181f, 0.0f, 0.0f)] // value: (ln(2)) + [InlineData(0.707106781f, 0.0f, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.0f, 0.0f)] // value: (pi / 4) + [InlineData(1.0f, 1.0f, 0.0f)] + [InlineData(1.12837917f, 1.0f, 0.0f)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.0f, 0.0f)] // value: (sqrt(2)) + [InlineData(1.44269504f, 1.0f, 0.0f)] // value: (log2(e)) + [InlineData(1.57079633f, 1.0f, 0.0f)] // value: (pi / 2) + [InlineData(2.30258509f, 2.0f, 0.0f)] // value: (ln(10)) + [InlineData(2.71828183f, 2.0f, 0.0f)] // value: (e) + [InlineData(3.14159265f, 3.0f, 0.0f)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Floor(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Floor(value), allowedVariance); + } + + [Fact] + public static void IEEERemainder() + { + Assert.Equal(-1.0f, MathF.IEEERemainder(3.0f, 2.0f)); + Assert.Equal(0.0f, MathF.IEEERemainder(4.0f, 2.0f)); + Assert.Equal(1.0f, MathF.IEEERemainder(10.0f, 3.0f)); + Assert.Equal(-1.0f, MathF.IEEERemainder(11.0f, 3.0f)); + Assert.Equal(-2.0f, MathF.IEEERemainder(28.0f, 5.0f)); + AssertExtensions.Equal(1.8f, MathF.IEEERemainder(17.8f, 4.0f), CrossPlatformMachineEpsilon * 10); + AssertExtensions.Equal(1.4f, MathF.IEEERemainder(17.8f, 4.1f), CrossPlatformMachineEpsilon * 10); + AssertExtensions.Equal(0.1000004f, MathF.IEEERemainder(-16.3f, 4.1f), CrossPlatformMachineEpsilon / 10); + AssertExtensions.Equal(1.4f, MathF.IEEERemainder(17.8f, -4.1f), CrossPlatformMachineEpsilon * 10); + AssertExtensions.Equal(-1.4f, MathF.IEEERemainder(-17.8f, -4.1f), CrossPlatformMachineEpsilon * 10); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, float.NaN, 0.0f)] + [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2)) + [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e)) + [InlineData(-0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(0.0432139183f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(0.0659880358f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) + [InlineData(0.1f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) + [InlineData(0.207879576f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(0.236290088f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(0.243116734f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(0.323557264f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(0.367879441f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.455938128f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(0.493068691f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(0.5f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(0.529077808f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(0.647721485f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(0.727377349f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(1.37480223f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(1.54387344f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) + [InlineData(1.89008116f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(2.0f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(2.02811498f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(2.19328005f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(2.71828183f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.09064302f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(4.11325038f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(4.23208611f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(4.81047738f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(10.0f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(15.1542622f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(23.1406926f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Log(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Log(value), allowedVariance); + } + + [Fact] + public static void LogWithBase() + { + Assert.Equal(1.0f, MathF.Log(3.0f, 3.0f)); + AssertExtensions.Equal(2.40217350f, MathF.Log(14.0f, 3.0f), CrossPlatformMachineEpsilon * 10); + Assert.Equal(float.NegativeInfinity, MathF.Log(0.0f, 3.0f)); + Assert.Equal(float.NaN, MathF.Log(-3.0f, 3.0f)); + Assert.Equal(float.NaN, MathF.Log(float.NaN, 3.0f)); + Assert.Equal(float.PositiveInfinity, MathF.Log(float.PositiveInfinity, 3.0f)); + Assert.Equal(float.NaN, MathF.Log(float.NegativeInfinity, 3.0f)); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) + [InlineData(-1.0f, float.NaN, 0.0f)] + [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2)) + [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e)) + [InlineData(-0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, 0.0f)] + [InlineData(0.000721784159f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) + [InlineData(0.00191301410f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) + [InlineData(0.00498212830f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) + [InlineData(0.0268660410f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) + [InlineData(0.0360831928f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) + [InlineData(0.0385288847f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) + [InlineData(0.0744082059f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) + [InlineData(0.1f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.163908636f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) + [InlineData(0.196287760f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) + [InlineData(0.202699566f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) + [InlineData(0.230876765f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) + [InlineData(0.367879441f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) + [InlineData(0.480496373f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) + [InlineData(1.0f, 0.0f, 0.0f)] + [InlineData(2.08118116f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) + [InlineData(2.71828183f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) value: (e) + [InlineData(4.33131503f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) + [InlineData(4.93340967f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) + [InlineData(5.09456117f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) + [InlineData(6.10095980f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) + [InlineData(10.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(13.4393779f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) + [InlineData(25.9545535f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) + [InlineData(27.7137338f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) + [InlineData(37.2217105f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) + [InlineData(200.717432f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) + [InlineData(522.735300f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) + [InlineData(1385.45573f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Log10(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Log10(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] + [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(float.NaN, 1.0f, float.NaN)] + [InlineData(1.0f, float.NaN, float.NaN)] + [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] + [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] + [InlineData(-0.0f, 0.0f, 0.0f)] +#if NETFRAMEWORK + [InlineData(0.0f, -0.0f, -0.0f)] +#else + [InlineData(0.0f, -0.0f, 0.0f)] +#endif + [InlineData(2.0f, -3.0f, 2.0f)] + [InlineData(-3.0f, 2.0f, 2.0f)] + [InlineData(3.0f, -2.0f, 3.0f)] + [InlineData(-2.0f, 3.0f, 3.0f)] + public static void Max(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, MathF.Max(x, y), 0.0f); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] + [InlineData(float.MinValue, float.MaxValue, float.MinValue)] + [InlineData(float.MaxValue, float.MinValue, float.MinValue)] + [InlineData(float.NaN, float.NaN, float.NaN)] + [InlineData(float.NaN, 1.0f, float.NaN)] + [InlineData(1.0f, float.NaN, float.NaN)] + [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] + [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] +#if NETFRAMEWORK + [InlineData(-0.0f, 0.0f, 0.0f)] +#else + [InlineData(-0.0f, 0.0f, -0.0f)] +#endif + [InlineData(0.0f, -0.0f, -0.0f)] + [InlineData(2.0f, -3.0f, -3.0f)] + [InlineData(-3.0f, 2.0f, -3.0f)] + [InlineData(3.0f, -2.0f, -2.0f)] + [InlineData(-2.0f, 3.0f, -2.0f)] + public static void Min(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, MathF.Min(x, y), 0.0f); + } + + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(float.NegativeInfinity, -1.0f, -0.0f, 0.0f)] + [InlineData(float.NegativeInfinity, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NegativeInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NegativeInfinity, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(float.NegativeInfinity, 1.0f, float.NegativeInfinity, 0.0f)] + [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-10.0f, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(-10.0f, -1.57079633f, float.NaN, 0.0f)] // y: -(pi / 2) + [InlineData(-10.0f, -1.0f, -0.1f, CrossPlatformMachineEpsilon)] + [InlineData(-10.0f, -0.785398163f, float.NaN, 0.0f)] // y: -(pi / 4) + [InlineData(-10.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-10.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-10.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-10.0f, 0.785398163f, float.NaN, 0.0f)] // y: (pi / 4) + [InlineData(-10.0f, 1.0f, -10.0f, CrossPlatformMachineEpsilon * 100)] + [InlineData(-10.0f, 1.57079633f, float.NaN, 0.0f)] // y: (pi / 2) + [InlineData(-10.0f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-2.71828183f, float.NegativeInfinity, 0.0f, 0.0f)] // x: -(e) + [InlineData(-2.71828183f, -1.57079633f, float.NaN, 0.0f)] // x: -(e) y: -(pi / 2) + [InlineData(-2.71828183f, -1.0f, -0.367879441f, CrossPlatformMachineEpsilon)] // x: -(e) + [InlineData(-2.71828183f, -0.785398163f, float.NaN, 0.0f)] // x: -(e) y: -(pi / 4) + [InlineData(-2.71828183f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: -(e) + [InlineData(-2.71828183f, float.NaN, float.NaN, 0.0f)] + [InlineData(-2.71828183f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: -(e) + [InlineData(-2.71828183f, 0.785398163f, float.NaN, 0.0f)] // x: -(e) y: (pi / 4) + [InlineData(-2.71828183f, 1.0f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // x: -(e) expected: (e) + [InlineData(-2.71828183f, 1.57079633f, float.NaN, 0.0f)] // x: -(e) y: (pi / 2) + [InlineData(-2.71828183f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-1.0f, -1.0f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-1.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-1.0f, 1.0f, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.0f, float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(-0.0f, -3.0f, float.NegativeInfinity, 0.0f)] + [InlineData(-0.0f, -2.0f, float.PositiveInfinity, 0.0f)] + [InlineData(-0.0f, -1.57079633f, float.PositiveInfinity, 0.0f)] // y: -(pi / 2) + [InlineData(-0.0f, -1.0f, float.NegativeInfinity, 0.0f)] + [InlineData(-0.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(-0.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.0f, 1.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, 1.57079633f, 0.0f, 0.0f)] // y: -(pi / 2) + [InlineData(-0.0f, 2.0f, 0.0f, 0.0f)] + [InlineData(-0.0f, 3.0f, -0.0f, 0.0f)] + [InlineData(-0.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(float.NaN, float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(float.NaN, -1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.NaN, float.NaN, 0.0f)] + [InlineData(float.NaN, 1.0f, float.NaN, 0.0f)] + [InlineData(float.NaN, float.PositiveInfinity, float.NaN, 0.0f)] + [InlineData(0.0f, float.NegativeInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -3.0f, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -2.0f, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -1.57079633f, float.PositiveInfinity, 0.0f)] // y: -(pi / 2) + [InlineData(0.0f, -1.0f, float.PositiveInfinity, 0.0f)] + [InlineData(0.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(0.0f, 1.0f, 0.0f, 0.0f)] + [InlineData(0.0f, 1.57079633f, 0.0f, 0.0f)] // y: -(pi / 2) + [InlineData(0.0f, 2.0f, 0.0f, 0.0f)] + [InlineData(0.0f, 3.0f, 0.0f, 0.0f)] + [InlineData(0.0f, float.PositiveInfinity, 0.0f, 0.0f)] + [InlineData(1.0f, float.NegativeInfinity, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, -1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, 1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.0f, float.PositiveInfinity, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(2.71828183f, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(2.71828183f, -3.14159265f, 0.0432139183f, CrossPlatformMachineEpsilon / 10)] // x: (e) y: -(pi) + [InlineData(2.71828183f, -2.71828183f, 0.0659880358f, CrossPlatformMachineEpsilon / 10)] // x: (e) y: -(e) + [InlineData(2.71828183f, -2.30258509f, 0.1f, CrossPlatformMachineEpsilon)] // x: (e) y: -(ln(10)) + [InlineData(2.71828183f, -1.57079633f, 0.207879576f, CrossPlatformMachineEpsilon)] // x: (e) y: -(pi / 2) + [InlineData(2.71828183f, -1.44269504f, 0.236290088f, CrossPlatformMachineEpsilon)] // x: (e) y: -(log2(e)) + [InlineData(2.71828183f, -1.41421356f, 0.243116734f, CrossPlatformMachineEpsilon)] // x: (e) y: -(sqrt(2)) + [InlineData(2.71828183f, -1.12837917f, 0.323557264f, CrossPlatformMachineEpsilon)] // x: (e) y: -(2 / sqrt(pi)) + [InlineData(2.71828183f, -1.0f, 0.367879441f, CrossPlatformMachineEpsilon)] // x: (e) + [InlineData(2.71828183f, -0.785398163f, 0.455938128f, CrossPlatformMachineEpsilon)] // x: (e) y: -(pi / 4) + [InlineData(2.71828183f, -0.707106781f, 0.493068691f, CrossPlatformMachineEpsilon)] // x: (e) y: -(1 / sqrt(2)) + [InlineData(2.71828183f, -0.693147181f, 0.5f, CrossPlatformMachineEpsilon)] // x: (e) y: -(ln(2)) + [InlineData(2.71828183f, -0.636619772f, 0.529077808f, CrossPlatformMachineEpsilon)] // x: (e) y: -(2 / pi) + [InlineData(2.71828183f, -0.434294482f, 0.647721485f, CrossPlatformMachineEpsilon)] // x: (e) y: -(log10(e)) + [InlineData(2.71828183f, -0.318309886f, 0.727377349f, CrossPlatformMachineEpsilon)] // x: (e) y: -(1 / pi) + [InlineData(2.71828183f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: (e) + [InlineData(2.71828183f, float.NaN, float.NaN, 0.0f)] + [InlineData(2.71828183f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] // x: (e) + [InlineData(2.71828183f, 0.318309886f, 1.37480223f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / pi) + [InlineData(2.71828183f, 0.434294482f, 1.54387344f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log10(e)) + [InlineData(2.71828183f, 0.636619772f, 1.89008116f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / pi) + [InlineData(2.71828183f, 0.693147181f, 2.0f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (ln(2)) + [InlineData(2.71828183f, 0.707106781f, 2.02811498f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / sqrt(2)) + [InlineData(2.71828183f, 0.785398163f, 2.19328005f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 4) + [InlineData(2.71828183f, 1.0f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // x: (e) expected: (e) + [InlineData(2.71828183f, 1.12837917f, 3.09064302f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / sqrt(pi)) + [InlineData(2.71828183f, 1.41421356f, 4.11325038f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (sqrt(2)) + [InlineData(2.71828183f, 1.44269504f, 4.23208611f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log2(e)) + [InlineData(2.71828183f, 1.57079633f, 4.81047738f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 2) + [InlineData(2.71828183f, 2.30258509f, 10.0f, CrossPlatformMachineEpsilon * 100)] // x: (e) y: (ln(10)) + [InlineData(2.71828183f, 2.71828183f, 15.1542622f, CrossPlatformMachineEpsilon * 100)] // x: (e) y: (e) + [InlineData(2.71828183f, 3.14159265f, 23.1406926f, CrossPlatformMachineEpsilon * 100)] // x: (e) y: (pi) + [InlineData(2.71828183f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] // x: (e) + [InlineData(10.0f, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(10.0f, -3.14159265f, 0.000721784159f, CrossPlatformMachineEpsilon / 1000)] // y: -(pi) + [InlineData(10.0f, -2.71828183f, 0.00191301410f, CrossPlatformMachineEpsilon / 100)] // y: -(e) + [InlineData(10.0f, -2.30258509f, 0.00498212830f, CrossPlatformMachineEpsilon / 100)] // y: -(ln(10)) + [InlineData(10.0f, -1.57079633f, 0.0268660410f, CrossPlatformMachineEpsilon / 10)] // y: -(pi / 2) + [InlineData(10.0f, -1.44269504f, 0.0360831928f, CrossPlatformMachineEpsilon / 10)] // y: -(log2(e)) + [InlineData(10.0f, -1.41421356f, 0.0385288847f, CrossPlatformMachineEpsilon / 10)] // y: -(sqrt(2)) + [InlineData(10.0f, -1.12837917f, 0.0744082059f, CrossPlatformMachineEpsilon / 10)] // y: -(2 / sqrt(pi)) + [InlineData(10.0f, -1.0f, 0.1f, CrossPlatformMachineEpsilon)] + [InlineData(10.0f, -0.785398163f, 0.163908636f, CrossPlatformMachineEpsilon)] // y: -(pi / 4) + [InlineData(10.0f, -0.707106781f, 0.196287760f, CrossPlatformMachineEpsilon)] // y: -(1 / sqrt(2)) + [InlineData(10.0f, -0.693147181f, 0.202699566f, CrossPlatformMachineEpsilon)] // y: -(ln(2)) + [InlineData(10.0f, -0.636619772f, 0.230876765f, CrossPlatformMachineEpsilon)] // y: -(2 / pi) + [InlineData(10.0f, -0.434294482f, 0.367879441f, CrossPlatformMachineEpsilon)] // y: -(log10(e)) + [InlineData(10.0f, -0.318309886f, 0.480496373f, CrossPlatformMachineEpsilon)] // y: -(1 / pi) + [InlineData(10.0f, -0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(10.0f, float.NaN, float.NaN, 0.0f)] + [InlineData(10.0f, 0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(10.0f, 0.318309886f, 2.08118116f, CrossPlatformMachineEpsilon * 10)] // y: (1 / pi) + [InlineData(10.0f, 0.434294482f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // y: (log10(e)) expected: (e) + [InlineData(10.0f, 0.636619772f, 4.33131503f, CrossPlatformMachineEpsilon * 10)] // y: (2 / pi) + [InlineData(10.0f, 0.693147181f, 4.93340967f, CrossPlatformMachineEpsilon * 10)] // y: (ln(2)) + [InlineData(10.0f, 0.707106781f, 5.09456117f, CrossPlatformMachineEpsilon * 10)] // y: (1 / sqrt(2)) + [InlineData(10.0f, 0.785398163f, 6.10095980f, CrossPlatformMachineEpsilon * 10)] // y: (pi / 4) + [InlineData(10.0f, 1.0f, 10.0f, CrossPlatformMachineEpsilon * 100)] + [InlineData(10.0f, 1.12837917f, 13.4393779f, CrossPlatformMachineEpsilon * 100)] // y: (2 / sqrt(pi)) + [InlineData(10.0f, 1.41421356f, 25.9545535f, CrossPlatformMachineEpsilon * 100)] // y: (sqrt(2)) + [InlineData(10.0f, 1.44269504f, 27.7137338f, CrossPlatformMachineEpsilon * 100)] // y: (log2(e)) + [InlineData(10.0f, 1.57079633f, 37.2217105f, CrossPlatformMachineEpsilon * 100)] // y: (pi / 2) + [InlineData(10.0f, 2.30258509f, 200.717432f, CrossPlatformMachineEpsilon * 1000)] // y: (ln(10)) + [InlineData(10.0f, 2.71828183f, 522.735300f, CrossPlatformMachineEpsilon * 1000)] // y: (e) + [InlineData(10.0f, 3.14159265f, 1385.45573f, CrossPlatformMachineEpsilon * 10000)] // y: (pi) + [InlineData(10.0f, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [InlineData(float.PositiveInfinity, float.NegativeInfinity, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, -1.0f, 0.0f, 0.0f)] + [InlineData(float.PositiveInfinity, -0.0f, 1.0f, 0.0f)] + [InlineData(float.PositiveInfinity, float.NaN, float.NaN, 0.0f)] + [InlineData(float.PositiveInfinity, 0.0f, 1.0f, 0.0f)] + [InlineData(float.PositiveInfinity, 1.0f, float.PositiveInfinity, 0.0f)] + [InlineData(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Pow(float x, float y, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Pow(x, y), allowedVariance); + } + + public static IEnumerable Round_Digits_TestData + { + get + { + yield return new object[] { float.NaN, float.NaN, 3, MidpointRounding.ToEven }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 3, MidpointRounding.ToEven }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, 3, MidpointRounding.ToEven }; + yield return new object[] { 0, 0, 3, MidpointRounding.ToEven }; + yield return new object[] { 3.42156f, 3.422f, 3, MidpointRounding.ToEven }; + yield return new object[] { -3.42156f, -3.422f, 3, MidpointRounding.ToEven }; + + yield return new object[] { float.NaN, float.NaN, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { 0, 0, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { 3.42156f, 3.422f, 3, MidpointRounding.AwayFromZero }; + yield return new object[] { -3.42156f, -3.422f, 3, MidpointRounding.AwayFromZero }; + } + } + + [Fact] + public static void Round() + { + Assert.Equal(0.0f, MathF.Round(0.0f)); + Assert.Equal(1.0f, MathF.Round(1.4f)); + Assert.Equal(2.0f, MathF.Round(1.5f)); + Assert.Equal(2e7f, MathF.Round(2e7f)); + Assert.Equal(0.0f, MathF.Round(-0.0f)); + Assert.Equal(-1.0f, MathF.Round(-1.4f)); + Assert.Equal(-2.0f, MathF.Round(-1.5f)); + Assert.Equal(-2e7f, MathF.Round(-2e7f)); + } + + [Theory] + [InlineData(MidpointRounding.ToEven)] + [InlineData(MidpointRounding.AwayFromZero)] + public static void Round_Digits_ByMidpointRounding(MidpointRounding mode) + { + Assert.Equal(float.PositiveInfinity, MathF.Round(float.PositiveInfinity, 3, mode)); + Assert.Equal(float.NegativeInfinity, MathF.Round(float.NegativeInfinity, 3, mode)); + } + + [Theory] + [MemberData(nameof(Round_Digits_TestData))] + public static void Round_Digits(float x, float expected, int digits, MidpointRounding mode) + { + AssertExtensions.Equal(expected, MathF.Round(x, digits, mode), CrossPlatformMachineEpsilon * 10); + } + + [Fact] + public static void Sign() + { + Assert.Equal(0, MathF.Sign(0.0f)); + Assert.Equal(0, MathF.Sign(-0.0f)); + Assert.Equal(-1, MathF.Sign(-3.14f)); + Assert.Equal(1, MathF.Sign(3.14f)); + Assert.Equal(-1, MathF.Sign(float.NegativeInfinity)); + Assert.Equal(1, MathF.Sign(float.PositiveInfinity)); + Assert.Throws(() => MathF.Sign(float.NaN)); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, -0.0f, CrossPlatformMachineEpsilon)] // value: -(pi) + [InlineData(-2.71828183f, -0.410781291f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, -0.743980337f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) + [InlineData(-1.44269504f, -0.991806244f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, -0.987765946f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -0.903719457f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -0.841470985f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, -0.707106781f, CrossPlatformMachineEpsilon)] // value: -(pi / 4), expected: -(1 / sqrt(2)) + [InlineData(-0.707106781f, -0.649636939f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.638961276f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.594480769f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.420770483f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.312961796f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.312961796f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.420770483f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.594480769f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.638961276f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.649636939f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.707106781f, CrossPlatformMachineEpsilon)] // value: (pi / 4), expected: (1 / sqrt(2)) + [InlineData(1.0f, 0.841470985f, CrossPlatformMachineEpsilon)] + [InlineData(1.12837917f, 0.903719457f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 0.987765946f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, 0.991806244f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.57079633f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 0.743980337f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.71828183f, 0.410781291f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Sin(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Sin(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)] + [InlineData(-3.14159265f, -11.5487394f, CrossPlatformMachineEpsilon * 100)] // value: -(pi) + [InlineData(-2.71828183f, -7.54413710f, CrossPlatformMachineEpsilon * 10)] // value: -(e) + [InlineData(-2.30258509f, -4.95f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10)) + [InlineData(-1.57079633f, -2.30129890f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2) + [InlineData(-1.44269504f, -1.99789801f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e)) + [InlineData(-1.41421356f, -1.93506682f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -1.38354288f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.17520119f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, -0.868670961f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) + [InlineData(-0.707106781f, -0.767523145f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.75f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.680501678f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.448075979f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.323712439f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.323712439f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.448075979f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.680501678f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.75f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.767523145f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.868670961f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 1.17520119f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.38354288f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.93506682f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 1.99789801f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 2.30129890f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 4.95f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, 7.54413710f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.14159265f, 11.5487394f, CrossPlatformMachineEpsilon * 100)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Sinh(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Sinh(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: (pi) + [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: (e) + [InlineData(-2.30258509f, float.NaN, 0.0f)] // value: (ln(10)) + [InlineData(-1.57079633f, float.NaN, 0.0f)] // value: (pi / 2) + [InlineData(-1.44269504f, float.NaN, 0.0f)] // value: (log2(e)) + [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2)) + [InlineData(-1.12837917f, float.NaN, 0.0f)] // value: (2 / sqrt(pi)) + [InlineData(-1.0f, float.NaN, 0.0f)] + [InlineData(-0.785398163f, float.NaN, 0.0f)] // value: (pi / 4) + [InlineData(-0.707106781f, float.NaN, 0.0f)] // value: (1 / sqrt(2)) + [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: (ln(2)) + [InlineData(-0.636619772f, float.NaN, 0.0f)] // value: (2 / pi) + [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: (log10(e)) + [InlineData(-0.318309886f, float.NaN, 0.0f)] // value: (1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.564189584f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.659010229f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.797884561f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.832554611f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.840896415f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.886226925f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 1.06225193f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 1.18920712f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 1.20112241f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, 1.25331414f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) + [InlineData(2.30258509f, 1.51742713f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, 1.64872127f, CrossPlatformMachineEpsilon * 10)] // value: (e) + [InlineData(3.14159265f, 1.77245385F, CrossPlatformMachineEpsilon * 10)] // value: (pi) + [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + public static void Sqrt(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Sqrt(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] + [InlineData(-3.14159265f, -0.0f, CrossPlatformMachineEpsilon)] // value: -(pi) + [InlineData(-2.71828183f, 0.450549534f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, 1.11340715f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10)) + [InlineData(-1.57079633f, 22877332.0f, 10.0f)] // value: -(pi / 2) + [InlineData(-1.44269504f, -7.76357567f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e)) + [InlineData(-1.41421356f, -6.33411917f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -2.11087684f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -1.55740772f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-0.785398163f, -1.0f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 4) + [InlineData(-0.707106781f, -0.854510432f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.830640878f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.739302950f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.463829067f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.329514733f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.329514733f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.463829067f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.739302950f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.830640878f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.854510432f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) + [InlineData(1.0f, 1.55740772f, CrossPlatformMachineEpsilon * 10)] + [InlineData(1.12837917f, 2.11087684f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 6.33411917f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) + [InlineData(1.44269504f, 7.76357567f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) + [InlineData(1.57079633f, -22877332.0f, 10.0f)] // value: (pi / 2) + [InlineData(2.30258509f, -1.11340715f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10)) + [InlineData(2.71828183f, -0.450549534f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, 0.0f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(float.PositiveInfinity, float.NaN, 0.0f)] + public static void Tan(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Tan(value), allowedVariance); + } + + [Theory] + [InlineData(float.NegativeInfinity, -1.0f, CrossPlatformMachineEpsilon * 10)] + [InlineData(-3.14159265f, -0.996272076f, CrossPlatformMachineEpsilon)] // value: -(pi) + [InlineData(-2.71828183f, -0.991328916f, CrossPlatformMachineEpsilon)] // value: -(e) + [InlineData(-2.30258509f, -0.980198020f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) + [InlineData(-1.57079633f, -0.917152336f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) + [InlineData(-1.44269504f, -0.894238946f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) + [InlineData(-1.41421356f, -0.888385562f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) + [InlineData(-1.12837917f, -0.810463806f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) + [InlineData(-1.0f, -0.761594156f, CrossPlatformMachineEpsilon)] + [InlineData(-0.785398163f, -0.655794203f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) + [InlineData(-0.707106781f, -0.608859365f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) + [InlineData(-0.693147181f, -0.6f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) + [InlineData(-0.636619772f, -0.562593600f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) + [InlineData(-0.434294482f, -0.408904012f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) + [InlineData(-0.318309886f, -0.307977913f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) + [InlineData(-0.0f, -0.0f, 0.0f)] + [InlineData(float.NaN, float.NaN, 0.0f)] + [InlineData(0.0f, 0.0f, 0.0f)] + [InlineData(0.318309886f, 0.307977913f, CrossPlatformMachineEpsilon)] // value: (1 / pi) + [InlineData(0.434294482f, 0.408904012f, CrossPlatformMachineEpsilon)] // value: (log10(e)) + [InlineData(0.636619772f, 0.562593600f, CrossPlatformMachineEpsilon)] // value: (2 / pi) + [InlineData(0.693147181f, 0.6f, CrossPlatformMachineEpsilon)] // value: (ln(2)) + [InlineData(0.707106781f, 0.608859365f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) + [InlineData(0.785398163f, 0.655794203f, CrossPlatformMachineEpsilon)] // value: (pi / 4) + [InlineData(1.0f, 0.761594156f, CrossPlatformMachineEpsilon)] + [InlineData(1.12837917f, 0.810463806f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) + [InlineData(1.41421356f, 0.888385562f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) + [InlineData(1.44269504f, 0.894238946f, CrossPlatformMachineEpsilon)] // value: (log2(e)) + [InlineData(1.57079633f, 0.917152336f, CrossPlatformMachineEpsilon)] // value: (pi / 2) + [InlineData(2.30258509f, 0.980198020f, CrossPlatformMachineEpsilon)] // value: (ln(10)) + [InlineData(2.71828183f, 0.991328916f, CrossPlatformMachineEpsilon)] // value: (e) + [InlineData(3.14159265f, 0.996272076f, CrossPlatformMachineEpsilon)] // value: (pi) + [InlineData(float.PositiveInfinity, 1.0f, CrossPlatformMachineEpsilon * 10)] + public static void Tanh(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, MathF.Tanh(value), allowedVariance); + } + + [Fact] + public static void Truncate() + { + Assert.Equal(0.0f, MathF.Truncate(0.12345f)); + Assert.Equal(3.0f, MathF.Truncate(3.14159f)); + Assert.Equal(-3.0f, MathF.Truncate(-3.14159f)); + } + + public static IEnumerable Round_ToEven_TestData() + { + yield return new object[] { 1f, 1f }; + yield return new object[] { 0.5f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 2f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 0.49999997f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 2f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 4.5f, 4f }; + yield return new object[] { 3.1415927f, 3f }; + yield return new object[] { 2.7182817f, 3f }; + yield return new object[] { 1385.4557f, 1385f }; + yield return new object[] { 3423.4343f, 3423f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.4f, 535345f }; + yield return new object[] { 535345.6f, 535346f }; + yield return new object[] { -2.7182817f, -3f }; + yield return new object[] { 10f, 10f }; + yield return new object[] { -10f, -10f }; + yield return new object[] { -0f, -0f }; + yield return new object[] { 0f, 0f }; + yield return new object[] { float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; + yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + } + + [Theory] + [MemberData(nameof(Round_ToEven_TestData))] + public static void Round_ToEven_0(float value, float expected) + { + // Math.Round has special fast paths when MidpointRounding is a const + // Don't replace it with a variable + Assert.Equal(expected, MathF.Round(value, MidpointRounding.ToEven)); + Assert.Equal(expected, MathF.Round(value, 0, MidpointRounding.ToEven)); + } + + public static IEnumerable Round_AwayFromZero_TestData() + { + yield return new object[] { 1f, 1f }; + yield return new object[] { 0.5f, 1f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 3f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 0.49999997f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 3f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 4.5f, 5f }; + yield return new object[] { 3.1415927f, 3f }; + yield return new object[] { 2.7182817f, 3f }; + yield return new object[] { 1385.4557f, 1385f }; + yield return new object[] { 3423.4343f, 3423f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.4f, 535345f }; + yield return new object[] { 535345.6f, 535346f }; + yield return new object[] { -2.7182817f, -3f }; + yield return new object[] { 10f, 10f }; + yield return new object[] { -10f, -10f }; + yield return new object[] { -0f, -0f }; + yield return new object[] { 0f, 0f }; + yield return new object[] { float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; + yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + } + + [Theory] + [MemberData(nameof(Round_AwayFromZero_TestData))] + public static void Round_AwayFromZero_0(float value, float expected) + { + // Math.Round has special fast paths when MidpointRounding is a const + // Don't replace it with a variable + Assert.Equal(expected, MathF.Round(value, MidpointRounding.AwayFromZero)); + Assert.Equal(expected, MathF.Round(value, 0, MidpointRounding.AwayFromZero)); + } + } +} diff --git a/src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj b/src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj new file mode 100644 index 00000000000000..8f2abec46041a7 --- /dev/null +++ b/src/libraries/Microsoft.Bcl.Numerics/tests/Microsoft.Bcl.Numerics.Tests.csproj @@ -0,0 +1,15 @@ + + + + $(NetFrameworkMinimum);$(NetCoreAppCurrent) + + + + + + + + + + + diff --git a/src/libraries/System.Numerics.Tensors/Directory.Build.props b/src/libraries/System.Numerics.Tensors/Directory.Build.props deleted file mode 100644 index 36078bccbf7aa8..00000000000000 --- a/src/libraries/System.Numerics.Tensors/Directory.Build.props +++ /dev/null @@ -1,8 +0,0 @@ - - - - - true - false - - \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/README.md b/src/libraries/System.Numerics.Tensors/README.md index 026563de81306d..6190da60e77c51 100644 --- a/src/libraries/System.Numerics.Tensors/README.md +++ b/src/libraries/System.Numerics.Tensors/README.md @@ -1,2 +1,3 @@ # System.Numerics.Tensors -This library has not been shipped publicly and is not accepting contributions at this time. \ No newline at end of file + +Provides APIs for performing primitive operations over tensors represented by spans of memory. diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs index 3161a4c7e780ce..50eaa00160e5cb 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs @@ -6,151 +6,47 @@ namespace System.Numerics.Tensors { - public static partial class ArrayTensorExtensions + public static partial class TensorPrimitives { - public static System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor(this System.Array array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor(this T[,,] array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor(this T[,] array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor(this T[] array) { throw null; } - public static System.Numerics.Tensors.SparseTensor ToSparseTensor(this System.Array array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.SparseTensor ToSparseTensor(this T[,,] array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.SparseTensor ToSparseTensor(this T[,] array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.SparseTensor ToSparseTensor(this T[] array) { throw null; } - public static System.Numerics.Tensors.DenseTensor ToTensor(this System.Array array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.DenseTensor ToTensor(this T[,,] array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.DenseTensor ToTensor(this T[,] array, bool reverseStride = false) { throw null; } - public static System.Numerics.Tensors.DenseTensor ToTensor(this T[] array) { throw null; } - } - public partial class CompressedSparseTensor : System.Numerics.Tensors.Tensor - { - public CompressedSparseTensor(System.Memory values, System.Memory compressedCounts, System.Memory indices, int nonZeroCount, System.ReadOnlySpan dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { } - public CompressedSparseTensor(System.ReadOnlySpan dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { } - public CompressedSparseTensor(System.ReadOnlySpan dimensions, int capacity, bool reverseStride = false) : base (default(System.Array), default(bool)) { } - public int Capacity { get { throw null; } } - public System.Memory CompressedCounts { get { throw null; } } - public System.Memory Indices { get { throw null; } } - public override T this[System.ReadOnlySpan indices] { get { throw null; } set { } } - public int NonZeroCount { get { throw null; } } - public System.Memory Values { get { throw null; } } - public override System.Numerics.Tensors.Tensor Clone() { throw null; } - public override System.Numerics.Tensors.Tensor CloneEmpty(System.ReadOnlySpan dimensions) { throw null; } - public override T GetValue(int index) { throw null; } - public override System.Numerics.Tensors.Tensor Reshape(System.ReadOnlySpan dimensions) { throw null; } - public override void SetValue(int index, T value) { } - public override System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor() { throw null; } - public override System.Numerics.Tensors.DenseTensor ToDenseTensor() { throw null; } - public override System.Numerics.Tensors.SparseTensor ToSparseTensor() { throw null; } - } - public partial class DenseTensor : System.Numerics.Tensors.Tensor - { - public DenseTensor(int length) : base (default(System.Array), default(bool)) { } - public DenseTensor(System.Memory memory, System.ReadOnlySpan dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { } - public DenseTensor(System.ReadOnlySpan dimensions, bool reverseStride = false) : base (default(System.Array), default(bool)) { } - public System.Memory Buffer { get { throw null; } } - public override System.Numerics.Tensors.Tensor Clone() { throw null; } - public override System.Numerics.Tensors.Tensor CloneEmpty(System.ReadOnlySpan dimensions) { throw null; } - protected override void CopyTo(T[] array, int arrayIndex) { } - public override T GetValue(int index) { throw null; } - protected override int IndexOf(T item) { throw null; } - public override System.Numerics.Tensors.Tensor Reshape(System.ReadOnlySpan dimensions) { throw null; } - public override void SetValue(int index, T value) { } - } - public partial class SparseTensor : System.Numerics.Tensors.Tensor - { - public SparseTensor(System.ReadOnlySpan dimensions, bool reverseStride = false, int capacity = 0) : base (default(System.Array), default(bool)) { } - public int NonZeroCount { get { throw null; } } - public override System.Numerics.Tensors.Tensor Clone() { throw null; } - public override System.Numerics.Tensors.Tensor CloneEmpty(System.ReadOnlySpan dimensions) { throw null; } - public override T GetValue(int index) { throw null; } - public override System.Numerics.Tensors.Tensor Reshape(System.ReadOnlySpan dimensions) { throw null; } - public override void SetValue(int index, T value) { } - public override System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor() { throw null; } - public override System.Numerics.Tensors.DenseTensor ToDenseTensor() { throw null; } - public override System.Numerics.Tensors.SparseTensor ToSparseTensor() { throw null; } - } - public static partial class Tensor - { - public static System.Numerics.Tensors.Tensor CreateFromDiagonal(System.Numerics.Tensors.Tensor diagonal) { throw null; } - public static System.Numerics.Tensors.Tensor CreateFromDiagonal(System.Numerics.Tensors.Tensor diagonal, int offset) { throw null; } - public static System.Numerics.Tensors.Tensor CreateIdentity(int size) { throw null; } - public static System.Numerics.Tensors.Tensor CreateIdentity(int size, bool columMajor) { throw null; } - public static System.Numerics.Tensors.Tensor CreateIdentity(int size, bool columMajor, T oneValue) { throw null; } - } - public abstract partial class Tensor : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList, System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable - { - protected Tensor(System.Array fromArray, bool reverseStride) { } - protected Tensor(int length) { } - protected Tensor(System.ReadOnlySpan dimensions, bool reverseStride) { } - public System.ReadOnlySpan Dimensions { get { throw null; } } - public bool IsFixedSize { get { throw null; } } - public bool IsReadOnly { get { throw null; } } - public bool IsReversedStride { get { throw null; } } - public virtual T this[params int[] indices] { get { throw null; } set { } } - public virtual T this[System.ReadOnlySpan indices] { get { throw null; } set { } } - public long Length { get { throw null; } } - public int Rank { get { throw null; } } - public System.ReadOnlySpan Strides { get { throw null; } } - int System.Collections.Generic.ICollection.Count { get { throw null; } } - T System.Collections.Generic.IList.this[int index] { get { throw null; } set { } } - int System.Collections.Generic.IReadOnlyCollection.Count { get { throw null; } } - T System.Collections.Generic.IReadOnlyList.this[int index] { get { throw null; } } - int System.Collections.ICollection.Count { get { throw null; } } - bool System.Collections.ICollection.IsSynchronized { get { throw null; } } - object System.Collections.ICollection.SyncRoot { get { throw null; } } - object? System.Collections.IList.this[int index] { get { throw null; } set { } } - public abstract System.Numerics.Tensors.Tensor Clone(); - public virtual System.Numerics.Tensors.Tensor CloneEmpty() { throw null; } - public virtual System.Numerics.Tensors.Tensor CloneEmpty(System.ReadOnlySpan dimensions) { throw null; } - public virtual System.Numerics.Tensors.Tensor CloneEmpty() { throw null; } - public abstract System.Numerics.Tensors.Tensor CloneEmpty(System.ReadOnlySpan dimensions); - public static int Compare(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) { throw null; } - protected virtual bool Contains(T item) { throw null; } - protected virtual void CopyTo(T[] array, int arrayIndex) { } - public static bool Equals(System.Numerics.Tensors.Tensor left, System.Numerics.Tensors.Tensor right) { throw null; } - public virtual void Fill(T value) { } - public string GetArrayString(bool includeWhitespace = true) { throw null; } - public System.Numerics.Tensors.Tensor GetDiagonal() { throw null; } - public System.Numerics.Tensors.Tensor GetDiagonal(int offset) { throw null; } - public System.Numerics.Tensors.Tensor GetTriangle() { throw null; } - public System.Numerics.Tensors.Tensor GetTriangle(int offset) { throw null; } - public System.Numerics.Tensors.Tensor GetUpperTriangle() { throw null; } - public System.Numerics.Tensors.Tensor GetUpperTriangle(int offset) { throw null; } - public abstract T GetValue(int index); - protected virtual int IndexOf(T item) { throw null; } - public abstract System.Numerics.Tensors.Tensor Reshape(System.ReadOnlySpan dimensions); - public abstract void SetValue(int index, T value); - public struct Enumerator : System.Collections.Generic.IEnumerator - { - public T Current { get; private set; } - object? System.Collections.IEnumerator.Current => throw null; - public bool MoveNext() => throw null; - public void Reset() { } - public void Dispose() { } - } - public Enumerator GetEnumerator() => throw null; - void System.Collections.Generic.ICollection.Add(T item) { } - void System.Collections.Generic.ICollection.Clear() { } - bool System.Collections.Generic.ICollection.Contains(T item) { throw null; } - void System.Collections.Generic.ICollection.CopyTo(T[] array, int arrayIndex) { } - bool System.Collections.Generic.ICollection.Remove(T item) { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.Generic.IList.IndexOf(T item) { throw null; } - void System.Collections.Generic.IList.Insert(int index, T item) { } - void System.Collections.Generic.IList.RemoveAt(int index) { } - void System.Collections.ICollection.CopyTo(System.Array array, int index) { } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.IList.Add(object? value) { throw null; } - void System.Collections.IList.Clear() { } - bool System.Collections.IList.Contains(object? value) { throw null; } - int System.Collections.IList.IndexOf(object? value) { throw null; } - void System.Collections.IList.Insert(int index, object? value) { } - void System.Collections.IList.Remove(object? value) { } - void System.Collections.IList.RemoveAt(int index) { } - int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } - int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - public virtual System.Numerics.Tensors.CompressedSparseTensor ToCompressedSparseTensor() { throw null; } - public virtual System.Numerics.Tensors.DenseTensor ToDenseTensor() { throw null; } - public virtual System.Numerics.Tensors.SparseTensor ToSparseTensor() { throw null; } + public static void Add(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { } + public static void Add(System.ReadOnlySpan x, float y, System.Span destination) { } + public static void AddMultiply(System.ReadOnlySpan x, System.ReadOnlySpan y, System.ReadOnlySpan multiplier, System.Span destination) { } + public static void AddMultiply(System.ReadOnlySpan x, System.ReadOnlySpan y, float multiplier, System.Span destination) { } + public static void AddMultiply(System.ReadOnlySpan x, float y, System.ReadOnlySpan multiplier, System.Span destination) { } + public static void Cosh(System.ReadOnlySpan x, System.Span destination) { } + public static float CosineSimilarity(System.ReadOnlySpan x, System.ReadOnlySpan y) { throw null; } + public static float Distance(System.ReadOnlySpan x, System.ReadOnlySpan y) { throw null; } + public static void Divide(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { } + public static void Divide(System.ReadOnlySpan x, float y, System.Span destination) { } + public static float Dot(System.ReadOnlySpan x, System.ReadOnlySpan y) { throw null; } + public static void Exp(System.ReadOnlySpan x, System.Span destination) { } + public static int IndexOfMax(System.ReadOnlySpan x) { throw null; } + public static int IndexOfMaxMagnitude(System.ReadOnlySpan x) { throw null; } + public static int IndexOfMin(System.ReadOnlySpan x) { throw null; } + public static int IndexOfMinMagnitude(System.ReadOnlySpan x) { throw null; } + public static float L2Normalize(System.ReadOnlySpan x) { throw null; } + public static void Log(System.ReadOnlySpan x, System.Span destination) { } + public static float Max(System.ReadOnlySpan x) { throw null; } + public static float MaxMagnitude(System.ReadOnlySpan x) { throw null; } + public static float Min(System.ReadOnlySpan x) { throw null; } + public static float MinMagnitude(System.ReadOnlySpan x) { throw null; } + public static void Multiply(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { } + public static void Multiply(System.ReadOnlySpan x, float y, System.Span destination) { } + public static void MultiplyAdd(System.ReadOnlySpan x, System.ReadOnlySpan y, System.ReadOnlySpan addend, System.Span destination) { } + public static void MultiplyAdd(System.ReadOnlySpan x, System.ReadOnlySpan y, float addend, System.Span destination) { } + public static void MultiplyAdd(System.ReadOnlySpan x, float y, System.ReadOnlySpan addend, System.Span destination) { } + public static void Negate(System.ReadOnlySpan x, System.Span destination) { } + public static float Product(System.ReadOnlySpan x) { throw null; } + public static float ProductOfDifferences(System.ReadOnlySpan x, System.ReadOnlySpan y) { throw null; } + public static float ProductOfSums(System.ReadOnlySpan x, System.ReadOnlySpan y) { throw null; } + public static void Sigmoid(System.ReadOnlySpan x, System.Span destination) { } + public static void Sinh(System.ReadOnlySpan x, System.Span destination) { } + public static void SoftMax(System.ReadOnlySpan x, System.Span destination) { } + public static void Subtract(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { } + public static void Subtract(System.ReadOnlySpan x, float y, System.Span destination) { } + public static float Sum(System.ReadOnlySpan x) { throw null; } + public static float SumOfMagnitudes(System.ReadOnlySpan x) { throw null; } + public static float SumOfSquares(System.ReadOnlySpan x) { throw null; } + public static void Tanh(System.ReadOnlySpan x, System.Span destination) { } } } diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj index cabfe50e267cfb..89bdef6ea38ed9 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj @@ -1,4 +1,5 @@ + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) @@ -7,7 +8,12 @@ + + + + + \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs new file mode 100644 index 00000000000000..1cde4351546b26 --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.netcore.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + public static void ConvertToHalf(System.ReadOnlySpan source, System.Span destination) { throw null; } + public static void ConvertToSingle(System.ReadOnlySpan source, System.Span destination) { throw null; } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/Properties/InternalsVisibleTo.cs b/src/libraries/System.Numerics.Tensors/src/Properties/InternalsVisibleTo.cs deleted file mode 100644 index 2b044e474d570a..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/Properties/InternalsVisibleTo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("System.Numerics.Tensors.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] diff --git a/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx b/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx index 57f792dde51dc2..45f0d8fa17893a 100644 --- a/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx +++ b/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx @@ -117,52 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Array must contain elements. + + Destination is too short. - - Cannot compare {0} to {1}. + + Input span arguments must not be empty. - - Cannot compare {0} to {1} with different dimension {2}, {3} != {4}. - - - Cannot compare {0} with different dimension {1}, {2} != {3}. - - - Cannot compare {0} with Rank {1} to {2} with Rank {3}. - - - Cannot compute diagonal of {0} with Rank less than 2. - - - Cannot compute diagonal with offset {0}. - - - Tensor {0} must have at least one dimension. - - - Cannot compute triangle of {0} with Rank less than 2. - - - Cannot reshape array due to mismatch in lengths, currently {0} would become {1}. - - - Dimensions must be positive and non-zero. - - - Dimensions must contain elements. - - - Length of {0} ({1}) must match product of {2} ({3}). - - - The number of elements in the Tensor is greater than the available space from index to the end of the destination array. - - - Only single dimensional arrays are supported for the requested action. - - - The value "{0}" is not of type "{1}" and cannot be used in this generic collection. + + Input span arguments must all have the same length. \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj index 521f8055a4fa61..097fa244ad4913 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -1,30 +1,36 @@ + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true - - $(NoWarn);1591 true - Tensor class which represents and extends multi-dimensional arrays. - -Commonly Used Types: -System.Numerics.Tensors.Tensor<T> -System.Numerics.Tensors.CompressedSparseTensor<T> -System.Numerics.Tensors.DenseTensor<T> -System.Numerics.Tensors.SparseTensor<T> + Provides support for operating over tensors. + + true - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayTensorExtensions.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayTensorExtensions.cs deleted file mode 100644 index 05e12a62c990e4..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayTensorExtensions.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Numerics.Tensors -{ - public static class ArrayTensorExtensions - { - /// - /// Creates a copy of this single-dimensional array as a DenseTensor<T> - /// - /// Type contained in the array to copy to the DenseTensor<T>. - /// The array to create a DenseTensor<T> from. - /// A 1-dimensional DenseTensor<T> with the same length and content as . - public static DenseTensor ToTensor(this T[] array) - { - return new DenseTensor(array); - } - - /// - /// Creates a copy of this two-dimensional array as a DenseTensor<T> - /// - /// Type contained in the array to copy to the DenseTensor<T>. - /// The array to create a DenseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): row-major. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): column-major. - /// A 2-dimensional DenseTensor<T> with the same dimensions and content as . - public static DenseTensor ToTensor(this T[,] array, bool reverseStride = false) - { - return new DenseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this three-dimensional array as a DenseTensor<T> - /// - /// Type contained in the array to copy to the DenseTensor<T>. - /// The array to create a DenseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// A 3-dimensional DenseTensor<T> with the same dimensions and content as . - public static DenseTensor ToTensor(this T[,,] array, bool reverseStride = false) - { - return new DenseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this n-dimensional array as a DenseTensor<T> - /// - /// Type contained in the array to copy to the DenseTensor<T>. - /// The array to create a DenseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// A n-dimensional DenseTensor<T> with the same dimensions and content as . - public static DenseTensor ToTensor(this Array array, bool reverseStride = false) - { - return new DenseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this single-dimensional array as a SparseTensor<T> - /// - /// Type contained in the array to copy to the SparseTensor<T>. - /// The array to create a SparseTensor<T> from. - /// A 1-dimensional SparseTensor<T> with the same length and content as . - public static SparseTensor ToSparseTensor(this T[] array) - { - return new SparseTensor(array); - } - - /// - /// Creates a copy of this two-dimensional array as a SparseTensor<T> - /// - /// Type contained in the array to copy to the SparseTensor<T>. - /// The array to create a SparseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): row-major. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): column-major. - /// A 2-dimensional SparseTensor<T> with the same dimensions and content as . - public static SparseTensor ToSparseTensor(this T[,] array, bool reverseStride = false) - { - return new SparseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this three-dimensional array as a SparseTensor<T> - /// - /// Type contained in the array to copy to the SparseTensor<T>. - /// The array to create a SparseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// A 3-dimensional SparseTensor<T> with the same dimensions and content as . - public static SparseTensor ToSparseTensor(this T[,,] array, bool reverseStride = false) - { - return new SparseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this n-dimensional array as a SparseTensor<T> - /// - /// Type contained in the array to copy to the SparseTensor<T>. - /// The array to create a SparseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// A n-dimensional SparseTensor<T> with the same dimensions and content as . - public static SparseTensor ToSparseTensor(this Array array, bool reverseStride = false) - { - return new SparseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this single-dimensional array as a CompressedSparseTensor<T> - /// - /// Type contained in the array to copy to the CompressedSparseTensor<T>. - /// The array to create a CompressedSparseTensor<T> from. - /// A 1-dimensional CompressedSparseTensor<T> with the same length and content as . - public static CompressedSparseTensor ToCompressedSparseTensor(this T[] array) - { - return new CompressedSparseTensor(array); - } - - /// - /// Creates a copy of this two-dimensional array as a CompressedSparseTensor<T> - /// - /// Type contained in the array to copy to the CompressedSparseTensor<T>. - /// The array to create a CompressedSparseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): row-major. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): column-major. - /// A 2-dimensional CompressedSparseTensor<T> with the same dimensions and content as . - public static CompressedSparseTensor ToCompressedSparseTensor(this T[,] array, bool reverseStride = false) - { - return new CompressedSparseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this three-dimensional array as a CompressedSparseTensor<T> - /// - /// Type contained in the array to copy to the CompressedSparseTensor<T>. - /// The array to create a CompressedSparseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// A 3-dimensional CompressedSparseTensor<T> with the same dimensions and content as . - public static CompressedSparseTensor ToCompressedSparseTensor(this T[,,] array, bool reverseStride = false) - { - return new CompressedSparseTensor(array, reverseStride); - } - - /// - /// Creates a copy of this n-dimensional array as a CompressedSparseTensor<T> - /// - /// Type contained in the array to copy to the CompressedSparseTensor<T>. - /// The array to create a CompressedSparseTensor<T> from. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// A n-dimensional CompressedSparseTensor<T> with the same dimensions and content as . - public static CompressedSparseTensor ToCompressedSparseTensor(this Array array, bool reverseStride = false) - { - return new CompressedSparseTensor(array, reverseStride); - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayUtilities.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayUtilities.cs deleted file mode 100644 index 97152090dfea06..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/ArrayUtilities.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; - -namespace System.Numerics.Tensors -{ - internal static class ArrayUtilities - { - public const int StackallocMax = 16; - - public static long GetProduct(ReadOnlySpan dimensions, int startIndex = 0) - { - if (dimensions.Length == 0) - { - return 0; - } - - long product = 1; - for (int i = startIndex; i < dimensions.Length; i++) - { - if (dimensions[i] < 0) - { - throw new ArgumentOutOfRangeException($"{nameof(dimensions)}[{i}]"); - } - - // we use a long which should be much larger than is ever used here, - // but still force checked - checked - { - product *= dimensions[i]; - } - } - - return product; - } - - public static bool IsAscending(ReadOnlySpan values) - { - for (int i = 1; i < values.Length; i++) - { - if (values[i] < values[i - 1]) - { - return false; - } - } - - return true; - } - - public static bool IsDescending(ReadOnlySpan values) - { - for (int i = 1; i < values.Length; i++) - { - if (values[i] > values[i - 1]) - { - return false; - } - } - - return true; - } - - /// - /// Gets the set of strides that can be used to calculate the offset of n-dimensions in a 1-dimensional layout - /// - /// - /// - /// - public static int[] GetStrides(ReadOnlySpan dimensions, bool reverseStride = false) - { - int[] strides = new int[dimensions.Length]; - - int stride = 1; - if (reverseStride) - { - for (int i = 0; i < strides.Length; i++) - { - strides[i] = stride; - stride *= dimensions[i]; - } - } - else - { - for (int i = strides.Length - 1; i >= 0; i--) - { - strides[i] = stride; - stride *= dimensions[i]; - } - } - - return strides; - } - - public static void SplitStrides(int[] strides, int[] splitAxes, int[] newStrides, int stridesOffset, int[] splitStrides, int splitStridesOffset) - { - int newStrideIndex = 0; - for (int i = 0; i < strides.Length; i++) - { - int stride = strides[i]; - bool isSplit = false; - for (int j = 0; j < splitAxes.Length; j++) - { - if (splitAxes[j] == i) - { - splitStrides[splitStridesOffset + j] = stride; - isSplit = true; - break; - } - } - - if (!isSplit) - { - newStrides[stridesOffset + newStrideIndex++] = stride; - } - } - } - - /// - /// Calculates the 1-d index for n-d indices in layout specified by strides. - /// - /// - /// - /// - /// - public static int GetIndex(int[] strides, ReadOnlySpan indices, int startFromDimension = 0) - { - Debug.Assert(strides.Length == indices.Length); - - int index = 0; - for (int i = startFromDimension; i < indices.Length; i++) - { - index += strides[i] * indices[i]; - } - - return index; - } - - /// - /// Calculates the n-d indices from the 1-d index in a layout specified by strides - /// - /// - /// - /// - /// - /// - public static void GetIndices(ReadOnlySpan strides, bool reverseStride, int index, int[] indices, int startFromDimension = 0) - { - Debug.Assert(reverseStride ? IsAscending(strides) : IsDescending(strides), "Index decomposition requires ordered strides"); - Debug.Assert(strides.Length == indices.Length); - - int remainder = index; - for (int i = startFromDimension; i < strides.Length; i++) - { - // reverse the index for reverseStride so that we divide by largest stride first - var nIndex = reverseStride ? strides.Length - 1 - i : i; - - var stride = strides[nIndex]; - indices[nIndex] = remainder / stride; - remainder %= stride; - } - } - - /// - /// Calculates the n-d indices from the 1-d index in a layout specified by strides - /// - /// - /// - /// - /// - /// - public static void GetIndices(ReadOnlySpan strides, bool reverseStride, int index, Span indices, int startFromDimension = 0) - { - Debug.Assert(reverseStride ? IsAscending(strides) : IsDescending(strides), "Index decomposition requires ordered strides"); - Debug.Assert(strides.Length == indices.Length); - - int remainder = index; - for (int i = startFromDimension; i < strides.Length; i++) - { - // reverse the index for reverseStride so that we divide by largest stride first - var nIndex = reverseStride ? strides.Length - 1 - i : i; - - var stride = strides[nIndex]; - indices[nIndex] = remainder / stride; - remainder %= stride; - } - } - - /// - /// Takes an 1-d index over n-d sourceStrides and recalculates it assuming same n-d coordinates over a different n-d strides - /// - public static int TransformIndexByStrides(int index, int[] sourceStrides, bool sourceReverseStride, int[] transformStrides) - { - Debug.Assert(index >= 0); - Debug.Assert(sourceReverseStride ? IsAscending(sourceStrides) : IsDescending(sourceStrides), "Index decomposition requires ordered strides"); - Debug.Assert(sourceStrides.Length == transformStrides.Length); - - int transformIndex = 0; - int remainder = index; - - for (int i = 0; i < sourceStrides.Length; i++) - { - // reverse the index for reverseStride so that we divide by largest stride first - var nIndex = sourceReverseStride ? sourceStrides.Length - 1 - i : i; - - var sourceStride = sourceStrides[nIndex]; - var transformStride = transformStrides[nIndex]; - - transformIndex += transformStride * (remainder / sourceStride); - remainder %= sourceStride; - } - - return transformIndex; - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/CompressedSparseTensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/CompressedSparseTensor.cs deleted file mode 100644 index b41915acddd5ab..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/CompressedSparseTensor.cs +++ /dev/null @@ -1,517 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Linq; - -namespace System.Numerics.Tensors -{ - /// - /// Represents a tensor using compressed sparse format - /// For a two dimensional tensor this is referred to as compressed sparse row (CSR, CRS, Yale), compressed sparse column (CSC, CCS) - /// - /// In this format, data that is in the same value for the compressed dimension has locality - /// - /// In standard layout of a dense tensor, data with the same value for first dimensions has locality. - /// As such we'll use reverseStride = false (default) to mean that the first dimension is compressed (CSR) - /// and reverseStride = true to mean that the last dimension is compressed (CSC) - /// - /// - /// - public class CompressedSparseTensor : Tensor - { - private Memory values; - private readonly Memory compressedCounts; - private Memory indices; - - private int nonZeroCount; - - private readonly int[] nonCompressedStrides; - private readonly int compressedDimension; - - private const int defaultCapacity = 64; - - /// - /// Constructs a new CompressedSparseTensor of the specified dimensions and stride ordering. - /// - /// An span of integers that represent the size of each dimension of the CompressedSparseTensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - public CompressedSparseTensor(ReadOnlySpan dimensions, bool reverseStride = false) : this(dimensions, defaultCapacity, reverseStride) - { } - - /// - /// Constructs a new CompressedSparseTensor of the specified dimensions, initial capacity, and stride ordering. - /// - /// An span of integers that represent the size of each dimension of the CompressedSparseTensor to create. - /// The number of non-zero values this tensor can store without resizing. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - public CompressedSparseTensor(ReadOnlySpan dimensions, int capacity, bool reverseStride = false) : base(dimensions, reverseStride) - { - nonZeroCount = 0; - compressedDimension = reverseStride ? Rank - 1 : 0; - nonCompressedStrides = (int[])strides.Clone(); - nonCompressedStrides[compressedDimension] = 0; - var compressedDimensionLength = dimensions[compressedDimension]; - compressedCounts = new int[compressedDimensionLength + 1]; - values = new T[capacity]; - indices = new int[capacity]; - } - - /// - /// Constructs a new CompressedSparseTensor of the specified dimensions, wrapping existing backing memory for the contents. - /// Growing this CompressedSparseTensor will re-allocate the backing memory. - /// - /// Memory storing non-zero values to construct this tensor with. - /// Memory storing the counts of non-zero elements at each index of the compressed dimension. - /// Memory storing the linearized index (excluding the compressed dimension) of non-zero elements. - /// The number of valid entries (eg: non-zero values) in and . - /// An span of integers that represent the size of each dimension of the CompressedSparseTensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - public CompressedSparseTensor(Memory values, Memory compressedCounts, Memory indices, int nonZeroCount, ReadOnlySpan dimensions, bool reverseStride = false) : base(dimensions, reverseStride) - { - compressedDimension = reverseStride ? Rank - 1 : 0; - nonCompressedStrides = (int[])strides.Clone(); - nonCompressedStrides[compressedDimension] = 0; - this.values = values; - this.compressedCounts = compressedCounts; - this.indices = indices; - this.nonZeroCount = nonZeroCount; - } - - internal CompressedSparseTensor(Array fromArray, bool reverseStride = false) : base(fromArray, reverseStride) - { - nonZeroCount = 0; - compressedDimension = reverseStride ? Rank - 1 : 0; - nonCompressedStrides = (int[])strides.Clone(); - nonCompressedStrides[compressedDimension] = 0; - var compressedDimensionLength = dimensions[compressedDimension]; - compressedCounts = new int[compressedDimensionLength + 1]; - - int index = 0; - if (reverseStride) - { - // Array is always row-major - var sourceStrides = ArrayUtilities.GetStrides(dimensions); - - foreach (T item in fromArray) - { - if (!item!.Equals(Zero)) - { - var destIndex = ArrayUtilities.TransformIndexByStrides(index, sourceStrides, false, strides); - var compressedIndex = destIndex / strides[compressedDimension]; - var nonCompressedIndex = destIndex % strides[compressedDimension]; - - SetAt(item, compressedIndex, nonCompressedIndex); - } - - index++; - } - } - else - { - foreach (T item in fromArray) - { - if (!item!.Equals(Zero)) - { - var compressedIndex = index / strides[compressedDimension]; - var nonCompressedIndex = index % strides[compressedDimension]; - - SetAt(item, compressedIndex, nonCompressedIndex); - } - - index++; - } - } - } - - /// - /// Obtains the value at the specified indices - /// - /// A span of integers that represent the indices specifying the position of the element to get. - /// The value at the specified position in this Tensor. - public override T this[ReadOnlySpan indices] - { - get - { - var compressedIndex = indices[compressedDimension]; - var nonCompressedIndex = ArrayUtilities.GetIndex(nonCompressedStrides, indices); - - - if (TryFindIndex(compressedIndex, nonCompressedIndex, out int valueIndex)) - { - return values.Span[valueIndex]; - } - - return Zero; - } - - set - { - var compressedIndex = indices[compressedDimension]; - var nonCompressedIndex = ArrayUtilities.GetIndex(nonCompressedStrides, indices); - - SetAt(value, compressedIndex, nonCompressedIndex); - } - } - - /// - /// Gets the value at the specified index, where index is lineraized as a dot product between indices and strides. - /// - /// An integer index computed as a dot-product of indices. - /// The value at the specified position in this Tensor. - public override T GetValue(int index) - { - var compressedDimensionStride = strides[compressedDimension]; - Debug.Assert(compressedDimensionStride == strides.Max()); - - var compressedIndex = index / compressedDimensionStride; - var nonCompressedIndex = index % compressedDimensionStride; - - - if (TryFindIndex(compressedIndex, nonCompressedIndex, out int valueIndex)) - { - return values.Span[valueIndex]; - } - - return Zero; - } - - /// - /// Sets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The new value to set at the specified position in this Tensor. - public override void SetValue(int index, T value) - { - var compressedDimensionStride = strides[compressedDimension]; - Debug.Assert(compressedDimensionStride == strides.Max()); - - var compressedIndex = index / compressedDimensionStride; - var nonCompressedIndex = index % compressedDimensionStride; - - SetAt(value, compressedIndex, nonCompressedIndex); - - } - - /// - /// Gets the number of non-zero values this tensor can store without resizing. - /// - public int Capacity => values.Length; - - /// - /// Get's the number on non-zero values currently being stored in this tensor. - /// - public int NonZeroCount => nonZeroCount; - - /// - /// Memory storing non-zero values. - /// - public Memory Values => values; - - /// - /// Memory storing the counts of non-zero elements at each index of the compressed dimension. - /// - public Memory CompressedCounts => compressedCounts; - - /// - /// Memory storing the linearized index (excluding the compressed dimension) of non-zero elements. - /// - public Memory Indices => indices; - - private void EnsureCapacity(int min, int allocateIndex = -1) - { - if (values.Length < min) - { - var newCapacity = values.Length == 0 ? defaultCapacity : values.Length * 2; - - if (newCapacity > Length) - { - newCapacity = (int)Length; - } - - if (newCapacity < min) - { - newCapacity = min; - } - - Memory newValues = new T[newCapacity]; - Memory newIndices = new int[newCapacity]; - - if (nonZeroCount > 0) - { - if (allocateIndex == -1) - { - var valuesSpan = values.Span.Slice(0, nonZeroCount); - var indicesSpan = indices.Span.Slice(0, nonZeroCount); - - valuesSpan.CopyTo(newValues.Span); - indicesSpan.CopyTo(newIndices.Span); - } - else - { - Debug.Assert(allocateIndex <= nonZeroCount); - // leave a gap at allocateIndex - - // copy range before allocateIndex - if (allocateIndex > 0) - { - var valuesSpan = values.Span.Slice(0, allocateIndex); - var indicesSpan = indices.Span.Slice(0, allocateIndex); - - valuesSpan.CopyTo(newValues.Span); - indicesSpan.CopyTo(newIndices.Span); - } - - if (allocateIndex < nonZeroCount) - { - var valuesSpan = values.Span.Slice(allocateIndex, nonZeroCount - allocateIndex); - var indicesSpan = indices.Span.Slice(allocateIndex, nonZeroCount - allocateIndex); - - var newValuesSpan = newValues.Span.Slice(allocateIndex + 1, nonZeroCount - allocateIndex); - var newIndicesSpan = newIndices.Span.Slice(allocateIndex + 1, nonZeroCount - allocateIndex); - - valuesSpan.CopyTo(newValuesSpan); - indicesSpan.CopyTo(newIndicesSpan); - } - } - } - - values = newValues; - indices = newIndices; - } - } - - private void InsertAt(int valueIndex, T value, int compressedIndex, int nonCompressedIndex) - { - Debug.Assert(valueIndex <= nonZeroCount); - Debug.Assert(compressedIndex < compressedCounts.Length - 1); - - if (values.Length <= valueIndex) - { - // allocate a new array, leaving a gap - EnsureCapacity(valueIndex + 1, valueIndex); - } - else if (nonZeroCount != valueIndex) - { - // shift values to make a gap - values.Span.Slice(valueIndex, nonZeroCount - valueIndex).CopyTo(values.Span.Slice(valueIndex + 1)); - indices.Span.Slice(valueIndex, nonZeroCount - valueIndex).CopyTo(indices.Span.Slice(valueIndex + 1)); - } - - values.Span[valueIndex] = value; - indices.Span[valueIndex] = nonCompressedIndex; - - var compressedCountsSpan = compressedCounts.Span.Slice(compressedIndex + 1); - for (int i = 0; i < compressedCountsSpan.Length; i++) - { - compressedCountsSpan[i]++; - } - nonZeroCount++; - } - - private void RemoveAt(int valueIndex, int compressedIndex) - { - Debug.Assert(valueIndex < nonZeroCount); - Debug.Assert(compressedIndex < compressedCounts.Length - 1); - - // shift values to close the gap - values.Span.Slice(valueIndex + 1, nonZeroCount - valueIndex - 1).CopyTo(values.Span.Slice(valueIndex)); - indices.Span.Slice(valueIndex + 1, nonZeroCount - valueIndex - 1).CopyTo(indices.Span.Slice(valueIndex)); - - var compressedCountsSpan = compressedCounts.Span.Slice(compressedIndex + 1); - for (int i = 0; i < compressedCountsSpan.Length; i++) - { - compressedCountsSpan[i]--; - } - nonZeroCount--; - } - - private void SetAt(T value, int compressedIndex, int nonCompressedIndex) - { - bool isZero = value!.Equals(Zero); - - if (TryFindIndex(compressedIndex, nonCompressedIndex, out int valueIndex)) - { - if (isZero) - { - RemoveAt(valueIndex, compressedIndex); - } - else - { - values.Span[valueIndex] = value; - indices.Span[valueIndex] = nonCompressedIndex; - } - } - else if (!isZero) - { - InsertAt(valueIndex, value, compressedIndex, nonCompressedIndex); - } - } - - /// - /// Trys to find the place to store a value - /// - /// - /// - /// - /// True if element is found at specific index, false if no specific index is found and insertion point is returned - private bool TryFindIndex(int compressedIndex, int nonCompressedIndex, out int valueIndex) - { - if (nonZeroCount == 0) - { - valueIndex = 0; - return false; - } - - Debug.Assert(compressedIndex < compressedCounts.Length - 1); - - var compressedCountsSpan = compressedCounts.Span; - var lowerValueIndex = compressedCountsSpan[compressedIndex]; - var upperValueIndex = compressedCountsSpan[compressedIndex + 1]; - var indicesSpan = indices.Span; - - // could be a faster search - for (valueIndex = lowerValueIndex; valueIndex < upperValueIndex; valueIndex++) - { - if (indicesSpan[valueIndex] == nonCompressedIndex) - { - return true; - } - } - - return false; - } - - /// - /// Creates a shallow copy of this tensor, with new backing storage. - /// - /// A shallow copy of this tensor. - public override Tensor Clone() - { - return new CompressedSparseTensor(values.ToArray(), compressedCounts.ToArray(), indices.ToArray(), nonZeroCount, dimensions, IsReversedStride); - } - - /// - /// Creates a new Tensor of a different type with the specified dimensions and the same layout as this tensor with elements initialized to their default value. - /// - /// Type contained in the returned Tensor. - /// An span of integers that represent the size of each dimension of the CompressedSparseTensor to create. - /// A new tensor with the same layout as this tensor but different type and dimensions. - public override Tensor CloneEmpty(ReadOnlySpan dimensions) - { - return new CompressedSparseTensor(dimensions, IsReversedStride); - } - - /// - /// Reshapes the current tensor to new dimensions. Unlike other Tensor implementations, CompressedSparseTensor<T> must allocate new backing storage to represent a reshaped Tensor. - /// - /// An span of integers that represent the size of each dimension of the CompressedSparseTensor to create. - /// A new tensor that reinterprets the content of this tensor to new dimensions (assuming the same linear index for each element). - public override Tensor Reshape(ReadOnlySpan dimensions) - { - // reshape currently has shallow semantics which are not compatible with the backing storage for CompressedSparseTensor - // which bakes in information about dimensions (compressedCounts and indices) - - var newCompressedDimension = IsReversedStride ? dimensions.Length - 1 : 0; - var newCompressedDimensionLength = dimensions[newCompressedDimension]; - var newCompressedDimensionStride = (int)(Length / newCompressedDimensionLength); - - var newValues = (T[])values.ToArray(); - var newCompressedCounts = new int[newCompressedDimensionLength + 1]; - var newIndices = new int[indices.Length]; - - var compressedIndex = 0; - - var compressedCountsSpan = compressedCounts.Span; - var indicesSpan = indices.Span.Slice(0, nonZeroCount); - for (int valueIndex = 0; valueIndex < indicesSpan.Length; valueIndex++) - { - while (valueIndex >= compressedCountsSpan[compressedIndex + 1]) - { - compressedIndex++; - Debug.Assert(compressedIndex < compressedCounts.Length); - } - - var currentIndex = indicesSpan[valueIndex] + compressedIndex * strides[compressedDimension]; - - newIndices[valueIndex] = currentIndex % newCompressedDimensionStride; - - var newCompressedIndex = currentIndex / newCompressedDimensionStride; - newCompressedCounts[newCompressedIndex + 1] = valueIndex + 1; - } - - return new CompressedSparseTensor(newValues, newCompressedCounts, newIndices, nonZeroCount, dimensions, IsReversedStride); - } - - /// - /// Creates a copy of this tensor as a DenseTensor<T>. - /// - /// A copy of this tensor as a DenseTensor<T> - public override DenseTensor ToDenseTensor() - { - var denseTensor = new DenseTensor(Dimensions, reverseStride: IsReversedStride); - - var compressedIndex = 0; - - var compressedCountsSpan = compressedCounts.Span; - var indicesSpan = indices.Span.Slice(0, nonZeroCount); - var valuesSpan = values.Span.Slice(0, nonZeroCount); - for (int valueIndex = 0; valueIndex < valuesSpan.Length; valueIndex++) - { - while (valueIndex >= compressedCountsSpan[compressedIndex + 1]) - { - compressedIndex++; - Debug.Assert(compressedIndex < compressedCounts.Length); - } - - var index = indicesSpan[valueIndex] + compressedIndex * strides[compressedDimension]; - - denseTensor.SetValue(index, valuesSpan[valueIndex]); - } - - return denseTensor; - } - - /// - /// Creates a copy of this tensor as a new CompressedSparseTensor<T> eliminating any unused space in the backing storage. - /// - /// A copy of this tensor as a CompressedSparseTensor<T>. - public override CompressedSparseTensor ToCompressedSparseTensor() - { - // Create a copy of the backing storage, eliminating any unused space. - var newValues = values.Slice(0, nonZeroCount).ToArray(); - var newIndices = indices.Slice(0, nonZeroCount).ToArray(); - - return new CompressedSparseTensor(newValues, compressedCounts.ToArray(), newIndices, nonZeroCount, dimensions, IsReversedStride); - } - - /// - /// Creates a copy of this tensor as a SparseTensor<T>. - /// - /// A copy of this tensor as a SparseTensor<T>. - public override SparseTensor ToSparseTensor() - { - var sparseTensor = new SparseTensor(dimensions, capacity: NonZeroCount, reverseStride: IsReversedStride); - - var compressedIndex = 0; - - var compressedCountsSpan = compressedCounts.Span; - var indicesSpan = indices.Span.Slice(0, nonZeroCount); - var valuesSpan = values.Span.Slice(0, nonZeroCount); - for (int valueIndex = 0; valueIndex < valuesSpan.Length; valueIndex++) - { - while (valueIndex >= compressedCountsSpan[compressedIndex + 1]) - { - compressedIndex++; - Debug.Assert(compressedIndex < compressedCounts.Length); - } - - var index = indicesSpan[valueIndex] + compressedIndex * strides[compressedDimension]; - - sparseTensor.SetValue(index, valuesSpan[valueIndex]); - } - - return sparseTensor; - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/DenseTensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/DenseTensor.cs deleted file mode 100644 index 5f8715be3d18c8..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/DenseTensor.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.InteropServices; - -namespace System.Numerics.Tensors -{ - /// - /// Represents a multi-dimensional collection of objects of type T that can be accessed by indices. DenseTensor stores values in a contiguous sequential block of memory where all values are represented. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - public class DenseTensor : Tensor - { - private readonly Memory memory; - - internal DenseTensor(Array fromArray, bool reverseStride = false) : base(fromArray, reverseStride) - { - // copy initial array - var backingArray = new T[fromArray.Length]; - - int index = 0; - if (reverseStride) - { - // Array is always row-major - var sourceStrides = ArrayUtilities.GetStrides(dimensions); - - foreach (var item in fromArray) - { - var destIndex = ArrayUtilities.TransformIndexByStrides(index++, sourceStrides, false, strides); - backingArray[destIndex] = (T)item!; - } - } - else - { - foreach (var item in fromArray) - { - backingArray[index++] = (T)item!; - } - } - memory = backingArray; - } - - /// - /// Initializes a rank-1 Tensor using the specified . - /// - /// Size of the 1-dimensional tensor - public DenseTensor(int length) : base(length) - { - memory = new T[length]; - } - - /// - /// Initializes a rank-n Tensor using the dimensions specified in . - /// - /// An span of integers that represent the size of each dimension of the DenseTensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - public DenseTensor(ReadOnlySpan dimensions, bool reverseStride = false) : base(dimensions, reverseStride) - { - memory = new T[Length]; - } - - /// - /// Constructs a new DenseTensor of the specified dimensions, wrapping existing backing memory for the contents. - /// - /// - /// An span of integers that represent the size of each dimension of the DenseTensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - public DenseTensor(Memory memory, ReadOnlySpan dimensions, bool reverseStride = false) : base(dimensions, reverseStride) - { - this.memory = memory; - - if (Length != memory.Length) - { - throw new ArgumentException(SR.Format(SR.LengthMustMatch, nameof(memory), memory.Length, nameof(dimensions), Length)); - } - } - - /// - /// Memory storing backing values of this tensor. - /// - public Memory Buffer => memory; - - /// - /// Gets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The value at the specified position in this Tensor. - public override T GetValue(int index) - { - return Buffer.Span[index]; - } - - /// - /// Sets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The new value to set at the specified position in this Tensor. - public override void SetValue(int index, T value) - { - Buffer.Span[index] = value; - } - - protected override void CopyTo(T[] array, int arrayIndex) - { - if (array is null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (array.Length < arrayIndex + Length) - { - throw new ArgumentException(SR.NumberGreaterThenAvailableSpace, nameof(array)); - } - - Buffer.Span.CopyTo(array.AsSpan(arrayIndex)); - } - - protected override int IndexOf(T item) - { - // TODO: use Span.IndexOf when/if it removes the IEquatable type constraint - if (MemoryMarshal.TryGetArray(Buffer, out var arraySegment)) - { - var result = Array.IndexOf(arraySegment.Array!, item, arraySegment.Offset, arraySegment.Count); - if (result != -1) - { - result -= arraySegment.Offset; - } - return result; - } - else - { - return base.IndexOf(item); - } - } - - /// - /// Creates a shallow copy of this tensor, with new backing storage. - /// - /// A shallow copy of this tensor. - public override Tensor Clone() - { - return new DenseTensor(Buffer.ToArray(), dimensions, IsReversedStride); - } - - /// - /// Creates a new Tensor of a different type with the specified dimensions and the same layout as this tensor with elements initialized to their default value. - /// - /// Type contained in the returned Tensor. - /// An span of integers that represent the size of each dimension of the DenseTensor to create. - /// A new tensor with the same layout as this tensor but different type and dimensions. - public override Tensor CloneEmpty(ReadOnlySpan dimensions) - { - return new DenseTensor(dimensions, IsReversedStride); - } - - /// - /// Reshapes the current tensor to new dimensions, using the same backing storage. - /// - /// An span of integers that represent the size of each dimension of the DenseTensor to create. - /// A new tensor that reinterprets backing Buffer of this tensor with different dimensions. - public override Tensor Reshape(ReadOnlySpan dimensions) - { - if (dimensions.Length == 0) - { - throw new ArgumentException(SR.DimensionsMustContainElements, nameof(dimensions)); - } - - var newSize = ArrayUtilities.GetProduct(dimensions); - - if (newSize != Length) - { - throw new ArgumentException(SR.Format(SR.CannotReshapeArrayDueToMismatchInLengths, Length, newSize), nameof(dimensions)); - } - - return new DenseTensor(Buffer, dimensions, IsReversedStride); - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/SparseTensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/SparseTensor.cs deleted file mode 100644 index 83948a0b918b7d..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/SparseTensor.cs +++ /dev/null @@ -1,177 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Numerics.Tensors -{ - /// - /// Represents a multi-dimensional collection of objects of type T that can be accessed by indices. Unlike other Tensor<T> implementations SparseTensor<T> does not expose its backing storage. It is meant as an intermediate to be used to build other Tensors, such as CompressedSparseTensor. Unlike CompressedSparseTensor where insertions are O(n), insertions to SparseTensor<T> are nominally O(1). - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - public class SparseTensor : Tensor - { - private readonly Dictionary values; - /// - /// Constructs a new SparseTensor of the specified dimensions, initial capacity, and stride ordering. - /// - /// An span of integers that represent the size of each dimension of the SparseTensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - /// The number of non-zero values this tensor can store without resizing. - public SparseTensor(ReadOnlySpan dimensions, bool reverseStride = false, int capacity = 0) : base(dimensions, reverseStride) - { - values = new Dictionary(capacity); - } - - internal SparseTensor(Dictionary values, ReadOnlySpan dimensions, bool reverseStride = false) : base(dimensions, reverseStride) - { - this.values = values; - } - - internal SparseTensor(Array fromArray, bool reverseStride = false) : base(fromArray, reverseStride) - { - values = new Dictionary(fromArray.Length); - - int index = 0; - if (reverseStride) - { - // Array is always row-major - var sourceStrides = ArrayUtilities.GetStrides(dimensions); - - foreach (T item in fromArray) - { - if (!item!.Equals(Zero)) - { - var destIndex = ArrayUtilities.TransformIndexByStrides(index, sourceStrides, false, strides); - values[destIndex] = item; - } - - index++; - } - } - else - { - foreach (T item in fromArray) - { - if (!item!.Equals(Zero)) - { - values[index] = item; - } - - index++; - } - } - } - - /// - /// Gets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The value at the specified position in this Tensor. - public override T GetValue(int index) - { - - if (!values.TryGetValue(index, out T? value)) - { - value = Zero; - } - - return value; - } - - /// - /// Sets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The new value to set at the specified position in this Tensor. - public override void SetValue(int index, T value) - { - if (value!.Equals(Zero)) - { - values.Remove(index); - } - else - { - values[index] = value; - } - } - - /// - /// Get's the number on non-zero values currently being stored in this tensor. - /// - public int NonZeroCount => values.Count; - - /// - /// Creates a shallow copy of this tensor, with new backing storage. - /// - /// A shallow copy of this tensor. - public override Tensor Clone() - { - var valueCopy = new Dictionary(values); - return new SparseTensor(valueCopy, dimensions, IsReversedStride); - } - - /// - /// Creates a new Tensor of a different type with the specified dimensions and the same layout as this tensor with elements initialized to their default value. - /// - /// Type contained in the returned Tensor. - /// An span of integers that represent the size of each dimension of the SparseTensor to create. - /// A new tensor with the same layout as this tensor but different type and dimensions. - public override Tensor CloneEmpty(ReadOnlySpan dimensions) - { - return new SparseTensor(dimensions, IsReversedStride); - } - - /// - /// Reshapes the current tensor to new dimensions, using the same backing storage. - /// - /// An span of integers that represent the size of each dimension of the SparseTensor to create. - /// A new tensor that reinterprets backing storage of this tensor with different dimensions. - public override Tensor Reshape(ReadOnlySpan dimensions) - { - return new SparseTensor(values, dimensions, IsReversedStride); - } - - /// - /// Creates a copy of this tensor as a DenseTensor<T>. - /// - /// A copy of this tensor as a DenseTensor<T> - public override DenseTensor ToDenseTensor() - { - var denseTensor = new DenseTensor(Dimensions, reverseStride: IsReversedStride); - - // only set non-zero values - foreach (var pair in values) - { - denseTensor.SetValue(pair.Key, pair.Value); - } - - return denseTensor; - } - - /// - /// Creates a copy of this tensor as a new SparseTensor<T> eliminating any unused space in the backing storage. - /// - /// A copy of this tensor as a SparseTensor<T> eliminated any usused space in the backing storage. - public override SparseTensor ToSparseTensor() - { - var valueCopy = new Dictionary(values); - return new SparseTensor(valueCopy, dimensions, IsReversedStride); - } - - /// - /// Creates a copy of this tensor as a CompressedSparseTensor<T>. - /// - /// A copy of this tensor as a CompressedSparseTensor<T>. - public override CompressedSparseTensor ToCompressedSparseTensor() - { - var compressedSparseTensor = new CompressedSparseTensor(dimensions, capacity: NonZeroCount, reverseStride: IsReversedStride); - - foreach (var pair in values) - { - compressedSparseTensor.SetValue(pair.Key, pair.Value); - } - return compressedSparseTensor; - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/Tensor.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/Tensor.cs deleted file mode 100644 index f63547682dd24b..00000000000000 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/Tensor.cs +++ /dev/null @@ -1,1365 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace System.Numerics.Tensors -{ - /// - /// Various methods for creating and manipulating Tensor<T> - /// - public static partial class Tensor - { - /// - /// Creates an identity tensor of the specified size. An identity tensor is a two dimensional tensor with 1s in the diagonal. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - /// Width and height of the identity tensor to create. - /// a by with 1s along the diagonal and zeros elsewhere. - public static Tensor CreateIdentity(int size) - { - return CreateIdentity(size, false, Tensor.One); - } - - /// - /// Creates an identity tensor of the specified size and layout (row vs column major). An identity tensor is a two dimensional tensor with 1s in the diagonal. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - /// Width and height of the identity tensor to create. - /// >False to indicate that the first dimension is most minor (closest) and the last dimension is most major (farthest): row-major. True to indicate that the last dimension is most minor (closest together) and the first dimension is most major (farthest apart): column-major. - /// a by with 1s along the diagonal and zeros elsewhere. - public static Tensor CreateIdentity(int size, bool columMajor) - { - return CreateIdentity(size, columMajor, Tensor.One); - } - - /// - /// Creates an identity tensor of the specified size and layout (row vs column major) using the specified one value. An identity tensor is a two dimensional tensor with 1s in the diagonal. This may be used in case T is a type that doesn't have a known 1 value. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - /// Width and height of the identity tensor to create. - /// >False to indicate that the first dimension is most minor (closest) and the last dimension is most major (farthest): row-major. True to indicate that the last dimension is most minor (closest together) and the first dimension is most major (farthest apart): column-major. - /// Value of that is used along the diagonal. - /// a by with 1s along the diagonal and zeros elsewhere. - public static Tensor CreateIdentity(int size, bool columMajor, T oneValue) - { - Span dimensions = stackalloc int[2]; - dimensions[0] = dimensions[1] = size; - - var result = new DenseTensor(dimensions, columMajor); - - for (int i = 0; i < size; i++) - { - result.SetValue(i * size + i, oneValue); - } - - return result; - } - - /// - /// Creates a n+1-rank tensor using the specified n-rank diagonal. Values not on the diagonal will be filled with zeros. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - /// Tensor representing the diagonal to build the new tensor from. - /// A new tensor of the same layout and order as of one higher rank, with the values of along the diagonal and zeros elsewhere. - public static Tensor CreateFromDiagonal(Tensor diagonal) - { - return CreateFromDiagonal(diagonal, 0); - } - - /// - /// Creates a n+1-dimension tensor using the specified n-dimension diagonal at the specified offset from the center. Values not on the diagonal will be filled with zeros. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - /// Tensor representing the diagonal to build the new tensor from. - /// Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above. - /// A new tensor of the same layout and order as of one higher rank, with the values of along the specified diagonal and zeros elsewhere. - public static Tensor CreateFromDiagonal(Tensor diagonal, int offset) - { - if (diagonal.Rank < 1) - { - throw new ArgumentException(SR.Format(SR.MustHaveAtLeastOneDimension, nameof(diagonal)), nameof(diagonal)); - } - - int diagonalLength = diagonal.dimensions[0]; - - // TODO: allow specification of axis1 and axis2? - var rank = diagonal.dimensions.Length + 1; - Span dimensions = rank < ArrayUtilities.StackallocMax ? stackalloc int[rank] : new int[rank]; - - // assume square - var axisLength = diagonalLength + Math.Abs(offset); - dimensions[0] = dimensions[1] = axisLength; - - for (int i = 1; i < diagonal.dimensions.Length; i++) - { - dimensions[i + 1] = diagonal.dimensions[i]; - } - - var result = diagonal.CloneEmpty(dimensions); - - var sizePerDiagonal = diagonal.Length / diagonalLength; - - var diagProjectionStride = diagonal.IsReversedStride && diagonal.Rank > 1 ? diagonal.strides[1] : 1; - var resultProjectionStride = result.IsReversedStride && result.Rank > 2 ? result.strides[2] : 1; - - for (int diagIndex = 0; diagIndex < diagonalLength; diagIndex++) - { - var resultIndex0 = offset < 0 ? diagIndex - offset : diagIndex; - var resultIndex1 = offset > 0 ? diagIndex + offset : diagIndex; - - var resultBase = resultIndex0 * result.strides[0] + resultIndex1 * result.strides[1]; - var diagBase = diagIndex * diagonal.strides[0]; - - for (int diagProjectionOffset = 0; diagProjectionOffset < sizePerDiagonal; diagProjectionOffset++) - { - result.SetValue(resultBase + diagProjectionOffset * resultProjectionStride, - diagonal.GetValue(diagBase + diagProjectionOffset * diagProjectionStride)); - } - } - - return result; - } - } - - /// - /// Represents a multi-dimensional collection of objects of type T that can be accessed by indices. - /// - /// type contained within the Tensor. Typically a value type such as int, double, float, etc. - [DebuggerDisplay("{GetArrayString(false)}")] - // When we cross-compile for frameworks that expose ICloneable this must implement ICloneable as well. - public abstract class Tensor : IList, IList, IReadOnlyList, IStructuralComparable, IStructuralEquatable - { - internal static T Zero - { - get - { - if (typeof(T) == typeof(bool)) - { - return (T)(object)(false); - } - else if (typeof(T) == typeof(byte)) - { - return (T)(object)(byte)(0); - } - else if (typeof(T) == typeof(char)) - { - return (T)(object)(char)(0); - } - else if (typeof(T) == typeof(decimal)) - { - return (T)(object)(decimal)(0); - } - else if (typeof(T) == typeof(double)) - { - return (T)(object)(double)(0); - } - else if (typeof(T) == typeof(float)) - { - return (T)(object)(float)(0); - } - else if (typeof(T) == typeof(int)) - { - return (T)(object)(int)(0); - } - else if (typeof(T) == typeof(long)) - { - return (T)(object)(long)(0); - } - else if (typeof(T) == typeof(sbyte)) - { - return (T)(object)(sbyte)(0); - } - else if (typeof(T) == typeof(short)) - { - return (T)(object)(short)(0); - } - else if (typeof(T) == typeof(uint)) - { - return (T)(object)(uint)(0); - } - else if (typeof(T) == typeof(ulong)) - { - return (T)(object)(ulong)(0); - } - else if (typeof(T) == typeof(ushort)) - { - return (T)(object)(ushort)(0); - } - - throw new NotSupportedException(); - } - } - - internal static T One - { - get - { - if (typeof(T) == typeof(bool)) - { - return (T)(object)(true); - } - else if (typeof(T) == typeof(byte)) - { - return (T)(object)(byte)(1); - } - else if (typeof(T) == typeof(char)) - { - return (T)(object)(char)(1); - } - else if (typeof(T) == typeof(decimal)) - { - return (T)(object)(decimal)(1); - } - else if (typeof(T) == typeof(double)) - { - return (T)(object)(double)(1); - } - else if (typeof(T) == typeof(float)) - { - return (T)(object)(float)(1); - } - else if (typeof(T) == typeof(int)) - { - return (T)(object)(int)(1); - } - else if (typeof(T) == typeof(long)) - { - return (T)(object)(long)(1); - } - else if (typeof(T) == typeof(sbyte)) - { - return (T)(object)(sbyte)(1); - } - else if (typeof(T) == typeof(short)) - { - return (T)(object)(short)(1); - } - else if (typeof(T) == typeof(uint)) - { - return (T)(object)(uint)(1); - } - else if (typeof(T) == typeof(ulong)) - { - return (T)(object)(ulong)(1); - } - else if (typeof(T) == typeof(ushort)) - { - return (T)(object)(ushort)(1); - } - - throw new NotSupportedException(); - } - } - - internal readonly int[] dimensions; - internal readonly int[] strides; - private readonly bool isReversedStride; - - private readonly long length; - - /// - /// Initialize a 1-dimensional tensor of the specified length - /// - /// Size of the 1-dimensional tensor - protected Tensor(int length) - { - dimensions = new[] { length }; - strides = new[] { 1 }; - isReversedStride = false; - this.length = length; - } - - /// - /// Initialize an n-dimensional tensor with the specified dimensions and layout. ReverseStride=true gives a stride of 1-element witdth to the first dimension (0). ReverseStride=false gives a stride of 1-element width to the last dimension (n-1). - /// - /// An span of integers that represent the size of each dimension of the Tensor to create. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - protected Tensor(ReadOnlySpan dimensions, bool reverseStride) - { - if (dimensions.Length == 0) - { - throw new ArgumentException(SR.DimensionsMustContainElements, nameof(dimensions)); - } - - this.dimensions = new int[dimensions.Length]; - long size = 1; - for (int i = 0; i < dimensions.Length; i++) - { - if (dimensions[i] < 1) - { - throw new ArgumentOutOfRangeException(nameof(dimensions), SR.DimensionsMustBePositiveAndNonZero); - } - this.dimensions[i] = dimensions[i]; - size *= dimensions[i]; - } - - strides = ArrayUtilities.GetStrides(dimensions, reverseStride); - isReversedStride = reverseStride; - - length = size; - } - - /// - /// Initializes tensor with same dimensions as array, content of array is ignored. ReverseStride=true gives a stride of 1-element witdth to the first dimension (0). ReverseStride=false gives a stride of 1-element width to the last dimension (n-1). - /// - /// Array from which to derive dimensions. - /// False (default) to indicate that the first dimension is most major (farthest apart) and the last dimension is most minor (closest together): akin to row-major in a rank-2 tensor. True to indicate that the last dimension is most major (farthest apart) and the first dimension is most minor (closest together): akin to column-major in a rank-2 tensor. - protected Tensor(Array fromArray, bool reverseStride) - { - if (fromArray is null) - { - throw new ArgumentNullException(nameof(fromArray)); - } - - if (fromArray.Rank == 0) - { - throw new ArgumentException(SR.ArrayMustContainElements, nameof(fromArray)); - } - - dimensions = new int[fromArray.Rank]; - long size = 1; - for (int i = 0; i < dimensions.Length; i++) - { - dimensions[i] = fromArray.GetLength(i); - size *= dimensions[i]; - } - - strides = ArrayUtilities.GetStrides(dimensions, reverseStride); - isReversedStride = reverseStride; - - length = size; - } - - /// - /// Total length of the Tensor. - /// - public long Length => length; - - /// - /// Rank of the tensor: number of dimensions. - /// - public int Rank => dimensions.Length; - - /// - /// True if strides are reversed (AKA Column-major) - /// - public bool IsReversedStride => isReversedStride; - - /// - /// Returns a readonly view of the dimensions of this tensor. - /// - public ReadOnlySpan Dimensions => dimensions; - - /// - /// Returns a readonly view of the strides of this tensor. - /// - public ReadOnlySpan Strides => strides; - - /// - /// Sets all elements in Tensor to . - /// - /// Value to fill - public virtual void Fill(T value) - { - for (int i = 0; i < Length; i++) - { - SetValue(i, value); - } - } - - /// - /// Creates a shallow copy of this tensor, with new backing storage. - /// - /// A shallow copy of this tensor. - public abstract Tensor Clone(); - - /// - /// Creates a new Tensor with the same layout and dimensions as this tensor with elements initialized to their default value. - /// - /// A new Tensor with the same layout and dimensions as this tensor with elements initialized to their default value. - public virtual Tensor CloneEmpty() - { - return CloneEmpty(dimensions); - } - - /// - /// Creates a new Tensor with the specified dimensions and the same layout as this tensor with elements initialized to their default value. - /// - /// An span of integers that represent the size of each dimension of the DenseTensor to create. - /// A new Tensor with the same layout as this tensor and specified with elements initialized to their default value. - public virtual Tensor CloneEmpty(ReadOnlySpan dimensions) - { - return CloneEmpty(dimensions); - } - - /// - /// Creates a new Tensor of a different type with the same layout and size as this tensor with elements initialized to their default value. - /// - /// Type contained within the new Tensor. Typically a value type such as int, double, float, etc. - /// A new Tensor with the same layout and dimensions as this tensor with elements of type initialized to their default value. - public virtual Tensor CloneEmpty() - { - return CloneEmpty(dimensions); - } - - /// - /// Creates a new Tensor of a different type with the specified dimensions and the same layout as this tensor with elements initialized to their default value. - /// - /// Type contained within the new Tensor. Typically a value type such as int, double, float, etc. - /// An span of integers that represent the size of each dimension of the DenseTensor to create. - /// A new Tensor with the same layout as this tensor of specified with elements of type initialized to their default value. - public abstract Tensor CloneEmpty(ReadOnlySpan dimensions); - - /// - /// Gets the n-1 dimension diagonal from the n dimension tensor. - /// - /// An n-1 dimension tensor with the values from the main diagonal of this tensor. - public Tensor GetDiagonal() - { - return GetDiagonal(0); - } - - /// - /// Gets the n-1 dimension diagonal from the n dimension tensor at the specified offset from center. - /// - /// Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above. - /// An n-1 dimension tensor with the values from the specified diagonal of this tensor. - public Tensor GetDiagonal(int offset) - { - // Get diagonal of first two dimensions for all remaining dimensions - - // diagnonal is as follows: - // { 1, 2, 4 } - // { 8, 3, 9 } - // { 0, 7, 5 } - // The diagonal at offset 0 is { 1, 3, 5 } - // The diagonal at offset 1 is { 2, 9 } - // The diagonal at offset -1 is { 8, 7 } - - if (Rank < 2) - { - throw new InvalidOperationException(SR.Format(SR.CannotComputeDiagonal, nameof(Tensor))); - } - - // TODO: allow specification of axis1 and axis2? - var axisLength0 = dimensions[0]; - var axisLength1 = dimensions[1]; - - // the diagonal will be the length of the smaller axis - // if offset it positive, the length will shift along the second axis - // if the offset is negative, the length will shift along the first axis - // In that way the length of the diagonal will be - // Min(offset < 0 ? axisLength0 + offset : axisLength0, offset > 0 ? axisLength1 - offset : axisLength1) - // To illustrate, consider the following - // { 1, 2, 4, 3, 7 } - // { 8, 3, 9, 2, 6 } - // { 0, 7, 5, 2, 9 } - // The diagonal at offset 0 is { 1, 3, 5 }, Min(3, 5) = 3 - // The diagonal at offset 1 is { 2, 9, 2 }, Min(3, 5 - 1) = 3 - // The diagonal at offset 3 is { 3, 6 }, Min(3, 5 - 3) = 2 - // The diagonal at offset -1 is { 8, 7 }, Min(3 - 1, 5) = 2 - var offsetAxisLength0 = offset < 0 ? axisLength0 + offset : axisLength0; - var offsetAxisLength1 = offset > 0 ? axisLength1 - offset : axisLength1; - - var diagonalLength = Math.Min(offsetAxisLength0, offsetAxisLength1); - - if (diagonalLength <= 0) - { - throw new ArgumentException(SR.Format(SR.CannotComputeDiagonalWithOffset, offset), nameof(offset)); - } - - var newTensorRank = Rank - 1; - var newTensorDimensions = newTensorRank < ArrayUtilities.StackallocMax ? stackalloc int[newTensorRank] : new int[newTensorRank]; - newTensorDimensions[0] = diagonalLength; - - for (int i = 2; i < dimensions.Length; i++) - { - newTensorDimensions[i - 1] = dimensions[i]; - } - - var diagonalTensor = CloneEmpty(newTensorDimensions); - var sizePerDiagonal = diagonalTensor.Length / diagonalTensor.Dimensions[0]; - - var diagProjectionStride = diagonalTensor.IsReversedStride && diagonalTensor.Rank > 1 ? diagonalTensor.strides[1] : 1; - var sourceProjectionStride = IsReversedStride && Rank > 2 ? strides[2] : 1; - - for (int diagIndex = 0; diagIndex < diagonalLength; diagIndex++) - { - var sourceIndex0 = offset < 0 ? diagIndex - offset : diagIndex; - var sourceIndex1 = offset > 0 ? diagIndex + offset : diagIndex; - - var sourceBase = sourceIndex0 * strides[0] + sourceIndex1 * strides[1]; - var diagBase = diagIndex * diagonalTensor.strides[0]; - - for (int diagProjectionIndex = 0; diagProjectionIndex < sizePerDiagonal; diagProjectionIndex++) - { - diagonalTensor.SetValue(diagBase + diagProjectionIndex * diagProjectionStride, - GetValue(sourceBase + diagProjectionIndex * sourceProjectionStride)); - } - } - - return diagonalTensor; - } - - /// - /// Gets a tensor representing the elements below and including the diagonal, with the rest of the elements zero-ed. - /// - /// A tensor with the values from this tensor at and below the main diagonal and zeros elsewhere. - public Tensor GetTriangle() - { - return GetTriangle(0, upper: false); - } - - /// - /// Gets a tensor representing the elements below and including the specified diagonal, with the rest of the elements zero-ed. - /// - /// Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above. - /// A tensor with the values from this tensor at and below the specified diagonal and zeros elsewhere. - public Tensor GetTriangle(int offset) - { - return GetTriangle(offset, upper: false); - } - - /// - /// Gets a tensor representing the elements above and including the diagonal, with the rest of the elements zero-ed. - /// - /// A tensor with the values from this tensor at and above the main diagonal and zeros elsewhere. - public Tensor GetUpperTriangle() - { - return GetTriangle(0, upper: true); - } - - /// - /// Gets a tensor representing the elements above and including the specified diagonal, with the rest of the elements zero-ed. - /// - /// Offset of diagonal to set in returned tensor. 0 for the main diagonal, less than zero for diagonals below, greater than zero from diagonals above. - /// A tensor with the values from this tensor at and above the specified diagonal and zeros elsewhere. - public Tensor GetUpperTriangle(int offset) - { - return GetTriangle(offset, upper: true); - } - - private Tensor GetTriangle(int offset, bool upper) - { - if (Rank < 2) - { - throw new InvalidOperationException(SR.Format(SR.CannotComputeTriangle, nameof(Tensor))); - } - - // Similar to get diagonal except it gets every element below and including the diagonal. - - // TODO: allow specification of axis1 and axis2? - var axisLength0 = dimensions[0]; - var axisLength1 = dimensions[1]; - var diagonalLength = Math.Max(axisLength0, axisLength1); - - var result = CloneEmpty(); - - var projectionSize = Length / (axisLength0 * axisLength1); - var projectionStride = IsReversedStride && Rank > 2 ? strides[2] : 1; - - for (int diagIndex = 0; diagIndex < diagonalLength; diagIndex++) - { - // starting point for the tri - var triIndex0 = offset > 0 ? diagIndex - offset : diagIndex; - var triIndex1 = offset > 0 ? diagIndex : diagIndex + offset; - - // for lower triangle, iterate index0 keeping same index1 - // for upper triangle, iterate index1 keeping same index0 - - if (triIndex0 < 0) - { - if (upper) - { - // out of bounds, ignore this diagIndex. - continue; - } - else - { - // set index to 0 so that we can iterate on the remaining index0 values. - triIndex0 = 0; - } - } - - if (triIndex1 < 0) - { - if (upper) - { - // set index to 0 so that we can iterate on the remaining index1 values. - triIndex1 = 0; - } - else - { - // out of bounds, ignore this diagIndex. - continue; - } - } - - while ((triIndex1 < axisLength1) && (triIndex0 < axisLength0)) - { - var baseIndex = triIndex0 * strides[0] + triIndex1 * result.strides[1]; - - for (int projectionIndex = 0; projectionIndex < projectionSize; projectionIndex++) - { - var index = baseIndex + projectionIndex * projectionStride; - - result.SetValue(index, GetValue(index)); - } - - if (upper) - { - triIndex1++; - } - else - { - triIndex0++; - } - } - } - - return result; - } - - /// - /// Reshapes the current tensor to new dimensions, using the same backing storage if possible. - /// - /// An span of integers that represent the size of each dimension of the Tensor to create. - /// A new tensor that reinterprets this tensor with different dimensions. - public abstract Tensor Reshape(ReadOnlySpan dimensions); - - /// - /// Obtains the value at the specified indices - /// - /// A one-dimensional array of integers that represent the indices specifying the position of the element to get. - /// The value at the specified position in this Tensor. - public virtual T this[params int[] indices] - { - get - { - if (indices is null) - { - throw new ArgumentNullException(nameof(indices)); - } - - var span = new ReadOnlySpan(indices); - return this[span]; - } - - set - { - if (indices is null) - { - throw new ArgumentNullException(nameof(indices)); - } - - var span = new ReadOnlySpan(indices); - this[span] = value; - } - } - - /// - /// Obtains the value at the specified indices - /// - /// A span integers that represent the indices specifying the position of the element to get. - /// The value at the specified position in this Tensor. - public virtual T this[ReadOnlySpan indices] - { - get - { - return GetValue(ArrayUtilities.GetIndex(strides, indices)); - } - - set - { - SetValue(ArrayUtilities.GetIndex(strides, indices), value); - } - } - - /// - /// Gets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The value at the specified position in this Tensor. - public abstract T GetValue(int index); - - /// - /// Sets the value at the specified index, where index is a linearized version of n-dimension indices using strides. - /// - /// An integer index computed as a dot-product of indices. - /// The new value to set at the specified position in this Tensor. - public abstract void SetValue(int index, T value); - - /// - /// The type that implements enumerators for instances. - /// - public struct Enumerator : IEnumerator - { - private readonly Tensor _tensor; - private int _index; - - internal Enumerator(Tensor tensor) - { - Debug.Assert(tensor != null); - - _tensor = tensor; - _index = 0; - Current = default!; - } - - public T Current { get; private set; } - - object? IEnumerator.Current => Current; - - public bool MoveNext() - { - if (_index < _tensor.Length) - { - Current = _tensor.GetValue(_index); - ++_index; - return true; - } - else - { - Current = default!; - return false; - } - } - - /// - /// Resets the enumerator to the beginning. - /// - public void Reset() - { - _index = 0; - Current = default!; - } - - /// - /// Disposes the enumerator. - /// - public void Dispose() { } - } - - /// - /// Gets an enumerator that enumerates the elements of the . - /// - /// An enumerator for the current . - public Enumerator GetEnumerator() => new Enumerator(this); - - #region statics - /// - /// Performs a value comparison of the content and shape of two tensors. Two tensors are equal if they have the same shape and same value at every set of indices. If not equal a tensor is greater or less than another tensor based on the first non-equal element when enumerating in linear order. - /// - /// - /// - /// - public static int Compare(Tensor left, Tensor right) - { - return StructuralComparisons.StructuralComparer.Compare(left, right); - } - - /// - /// Performs a value equality comparison of the content of two tensors. Two tensors are equal if they have the same shape and same value at every set of indices. - /// - /// - /// - /// - public static bool Equals(Tensor left, Tensor right) - { - return StructuralComparisons.StructuralEqualityComparer.Equals(left, right); - } - #endregion - - #region IEnumerable members - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - #endregion - - #region ICollection members - int ICollection.Count => (int)Length; - - bool ICollection.IsSynchronized => false; - - object ICollection.SyncRoot => this; // backingArray.this? - - void ICollection.CopyTo(Array array, int index) - { - if (array is T[] destinationArray) - { - CopyTo(destinationArray, index); - } - else - { - if (array == null) - { - throw new ArgumentNullException(nameof(array)); - } - if (array.Rank != 1) - { - throw new ArgumentException(SR.OnlySingleDimensionalArraysSupported, nameof(array)); - } - if (array.Length < index + Length) - { - throw new ArgumentException(SR.NumberGreaterThenAvailableSpace, nameof(array)); - } - - for (int i = 0; i < length; i++) - { - array.SetValue(GetValue(i), index + i); - } - } - } - #endregion - - #region IList members - object? IList.this[int index] - { - get - { - return GetValue(index); - } - set - { - try - { - SetValue(index, (T)value!); - } - catch (InvalidCastException) - { - throw new ArgumentException(SR.Format(SR.ValueIsNotOfType, value, typeof(T))); - } - } - } - - public bool IsFixedSize => true; - - public bool IsReadOnly => false; - - int IList.Add(object? value) - { - throw new InvalidOperationException(); - } - - void IList.Clear() - { - Fill(default!); - } - - bool IList.Contains(object? value) - { - if (IsCompatibleObject(value!)) - { - return Contains((T)value!); - } - return false; - } - - int IList.IndexOf(object? value) - { - if (IsCompatibleObject(value!)) - { - return IndexOf((T)value!); - } - return -1; - } - - void IList.Insert(int index, object? value) - { - throw new InvalidOperationException(); - } - - void IList.Remove(object? value) - { - throw new InvalidOperationException(); - } - - void IList.RemoveAt(int index) - { - throw new InvalidOperationException(); - } - #endregion - - #region IEnumerable members - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - #endregion - - #region ICollection members - int ICollection.Count => (int)Length; - - void ICollection.Add(T item) - { - throw new InvalidOperationException(); - } - - void ICollection.Clear() - { - Fill(default!); - } - - bool ICollection.Contains(T item) - { - return Contains(item); - } - - /// - /// Determines whether an element is in the Tensor<T>. - /// - /// - /// The object to locate in the Tensor<T>. The value can be null for reference types. - /// - /// - /// true if item is found in the Tensor<T>; otherwise, false. - /// - protected virtual bool Contains(T item) - { - return Length != 0 && IndexOf(item) != -1; - } - - void ICollection.CopyTo(T[] array, int arrayIndex) - { - CopyTo(array, arrayIndex); - } - - /// - /// Copies the elements of the Tensor<T> to an Array, starting at a particular Array index. - /// - /// - /// The one-dimensional Array that is the destination of the elements copied from Tensor<T>. The Array must have zero-based indexing. - /// - /// - /// The zero-based index in array at which copying begins. - /// - protected virtual void CopyTo(T[] array, int arrayIndex) - { - if (array is null) - { - throw new ArgumentNullException(nameof(array)); - } - - if (array.Length < arrayIndex + Length) - { - throw new ArgumentException(SR.NumberGreaterThenAvailableSpace, nameof(array)); - } - - for (int i = 0; i < length; i++) - { - array[arrayIndex + i] = GetValue(i); - } - } - - bool ICollection.Remove(T item) - { - throw new InvalidOperationException(); - } - #endregion - - #region IReadOnlyCollection members - - int IReadOnlyCollection.Count => (int)Length; - - #endregion - - #region IList members - T IList.this[int index] - { - get { return GetValue(index); } - set { SetValue(index, value); } - } - - int IList.IndexOf(T item) - { - return IndexOf(item); - } - - /// - /// Determines the index of a specific item in the Tensor<T>. - /// - /// The object to locate in the Tensor<T>. - /// The index of item if found in the tensor; otherwise, -1. - protected virtual int IndexOf(T item) - { - for (int i = 0; i < Length; i++) - { - if (GetValue(i)!.Equals(item)) - { - return i; - } - } - - return -1; - } - - void IList.Insert(int index, T item) - { - throw new InvalidOperationException(); - } - - void IList.RemoveAt(int index) - { - throw new InvalidOperationException(); - } - #endregion - - #region IReadOnlyList members - - T IReadOnlyList.this[int index] => GetValue(index); - - #endregion - - #region IStructuralComparable members - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) - { - return 1; - } - - if (other is Tensor) - { - return CompareTo((Tensor)other, comparer); - } - - var otherArray = other as Array; - - if (otherArray != null) - { - return CompareTo(otherArray, comparer); - } - - throw new ArgumentException(SR.Format(SR.CannotCompare, nameof(Tensor), other.GetType()), nameof(other)); - } - - private int CompareTo(Tensor other, IComparer comparer) - { - if (Rank != other.Rank) - { - throw new ArgumentException(SR.Format(SR.CannotCompareWithRank, nameof(Tensor), Rank, nameof(other), other.Rank), nameof(other)); - } - - for (int i = 0; i < dimensions.Length; i++) - { - if (dimensions[i] != other.dimensions[i]) - { - throw new ArgumentException(SR.Format(SR.CannotCompareWithDifferentDimension, nameof(Tensor), i, dimensions[i], other.dimensions[i]), nameof(other)); - } - } - - int result = 0; - - if (IsReversedStride == other.IsReversedStride) - { - for (int i = 0; i < Length; i++) - { - result = comparer.Compare(GetValue(i), other.GetValue(i)); - if (result != 0) - { - break; - } - } - } - else - { - var indices = Rank < ArrayUtilities.StackallocMax ? stackalloc int[Rank] : new int[Rank]; - for (int i = 0; i < Length; i++) - { - ArrayUtilities.GetIndices(strides, IsReversedStride, i, indices); - result = comparer.Compare(this[indices], other[indices]); - if (result != 0) - { - break; - } - } - } - - return result; - } - - private int CompareTo(Array other, IComparer comparer) - { - if (Rank != other.Rank) - { - throw new ArgumentException(SR.Format(SR.CannotCompareWithRank, nameof(Tensor), Rank, nameof(Array), other.Rank), nameof(other)); - } - - for (int i = 0; i < dimensions.Length; i++) - { - var otherDimension = other.GetLength(i); - if (dimensions[i] != otherDimension) - { - throw new ArgumentException(SR.Format(SR.CannotCompareToWithDifferentDimension, nameof(Tensor), nameof(Array), i, dimensions[i], otherDimension), nameof(other)); - } - } - - int result = 0; - var indices = new int[Rank]; - for (int i = 0; i < Length; i++) - { - ArrayUtilities.GetIndices(strides, IsReversedStride, i, indices); - - result = comparer.Compare(GetValue(i), other.GetValue(indices)); - - if (result != 0) - { - break; - } - } - - return result; - } - #endregion - - #region IStructuralEquatable members - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null) - { - return false; - } - - if (other is Tensor) - { - return Equals((Tensor)other, comparer); - } - - var otherArray = other as Array; - - if (otherArray != null) - { - return Equals(otherArray, comparer); - } - - throw new ArgumentException(SR.Format(SR.CannotCompare, nameof(Tensor), other.GetType()), nameof(other)); - } - - private bool Equals(Tensor other, IEqualityComparer comparer) - { - if (Rank != other.Rank) - { - throw new ArgumentException(SR.Format(SR.CannotCompareWithRank, nameof(Tensor), Rank, nameof(other), other.Rank), nameof(other)); - } - - for (int i = 0; i < dimensions.Length; i++) - { - if (dimensions[i] != other.dimensions[i]) - { - throw new ArgumentException(SR.Format(SR.CannotCompareWithDifferentDimension, nameof(Tensor), i, dimensions[i], other.dimensions[i]), nameof(other)); - } - } - - if (IsReversedStride == other.IsReversedStride) - { - for (int i = 0; i < Length; i++) - { - if (!comparer.Equals(GetValue(i), other.GetValue(i))) - { - return false; - } - } - } - else - { - var indices = Rank < ArrayUtilities.StackallocMax ? stackalloc int[Rank] : new int[Rank]; - for (int i = 0; i < Length; i++) - { - ArrayUtilities.GetIndices(strides, IsReversedStride, i, indices); - - if (!comparer.Equals(this[indices], other[indices])) - { - return false; - } - } - } - - return true; - } - - private bool Equals(Array other, IEqualityComparer comparer) - { - if (Rank != other.Rank) - { - throw new ArgumentException(SR.Format(SR.CannotCompareWithRank, nameof(Tensor), Rank, nameof(Array), other.Rank), nameof(other)); - } - - for (int i = 0; i < dimensions.Length; i++) - { - var otherDimension = other.GetLength(i); - if (dimensions[i] != otherDimension) - { - throw new ArgumentException(SR.Format(SR.CannotCompareToWithDifferentDimension, nameof(Tensor), nameof(Array), i, dimensions[i], otherDimension), nameof(other)); - } - } - - var indices = new int[Rank]; - for (int i = 0; i < Length; i++) - { - ArrayUtilities.GetIndices(strides, IsReversedStride, i, indices); - - if (!comparer.Equals(GetValue(i), other.GetValue(indices))) - { - return false; - } - } - - return true; - } - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - int hashCode = 0; - // this ignores shape, which is fine it just means we'll have hash collisions for things - // with the same content and different shape. - for (int i = 0; i < Length; i++) - { - hashCode ^= comparer.GetHashCode(GetValue(i)!); - } - - return hashCode; - } - #endregion - - #region Translations - - /// - /// Creates a copy of this tensor as a DenseTensor<T>. If this tensor is already a DenseTensor<T> calling this method is equivalent to calling Clone(). - /// - /// - public virtual DenseTensor ToDenseTensor() - { - var denseTensor = new DenseTensor(Dimensions, IsReversedStride); - for (int i = 0; i < Length; i++) - { - denseTensor.SetValue(i, GetValue(i)); - } - return denseTensor; - } - - - /// - /// Creates a copy of this tensor as a SparseTensor<T>. If this tensor is already a SparseTensor<T> calling this method is equivalent to calling Clone(). - /// - /// - public virtual SparseTensor ToSparseTensor() - { - var sparseTensor = new SparseTensor(Dimensions, IsReversedStride); - for (int i = 0; i < Length; i++) - { - sparseTensor.SetValue(i, GetValue(i)); - } - return sparseTensor; - } - - /// - /// Creates a copy of this tensor as a CompressedSparseTensor<T>. If this tensor is already a CompressedSparseTensor<T> calling this method is equivalent to calling Clone(). - /// - /// - public virtual CompressedSparseTensor ToCompressedSparseTensor() - { - var compressedSparseTensor = new CompressedSparseTensor(Dimensions, IsReversedStride); - for (int i = 0; i < Length; i++) - { - compressedSparseTensor.SetValue(i, GetValue(i)); - } - return compressedSparseTensor; - } - - #endregion - - public string GetArrayString(bool includeWhitespace = true) - { - var builder = new StringBuilder(); - - var strides = ArrayUtilities.GetStrides(dimensions); - var indices = new int[Rank]; - var innerDimension = Rank - 1; - var innerLength = dimensions[innerDimension]; - - int indent = 0; - for (int outerIndex = 0; outerIndex < Length; outerIndex += innerLength) - { - ArrayUtilities.GetIndices(strides, false, outerIndex, indices); - - while ((indent < innerDimension) && (indices[indent] == 0)) - { - // start up - if (includeWhitespace) - { - Indent(builder, indent); - } - indent++; - builder.Append('{'); - if (includeWhitespace) - { - builder.AppendLine(); - } - } - - for (int innerIndex = 0; innerIndex < innerLength; innerIndex++) - { - indices[innerDimension] = innerIndex; - - if ((innerIndex == 0)) - { - if (includeWhitespace) - { - Indent(builder, indent); - } - builder.Append('{'); - } - else - { - builder.Append(','); - } - builder.Append(this[indices]); - } - builder.Append('}'); - - for (int i = Rank - 2; i >= 0; i--) - { - var lastIndex = dimensions[i] - 1; - if (indices[i] == lastIndex) - { - // close out - --indent; - if (includeWhitespace) - { - builder.AppendLine(); - Indent(builder, indent); - } - builder.Append('}'); - } - else - { - builder.Append(','); - if (includeWhitespace) - { - builder.AppendLine(); - } - break; - } - } - } - - return builder.ToString(); - } - - private static void Indent(StringBuilder builder, int tabs, int spacesPerTab = 4) - { - for (int tab = 0; tab < tabs; tab++) - { - for (int space = 0; space < spacesPerTab; space++) - { - builder.Append(' '); - } - } - } - - private static bool IsCompatibleObject(object value) - { - // Non-null values are fine. Only accept nulls if T is a class or Nullable. - // Note that default(T) is not equal to null for value types except when T is Nullable. - return ((value is T) || (value == null && default(T) == null)); - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs new file mode 100644 index 00000000000000..a400095b08ad39 --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs @@ -0,0 +1,824 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Numerics.Tensors +{ + /// Performs primitive tensor operations over spans of memory. + public static partial class TensorPrimitives + { + /// Computes the element-wise result of: + . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = [i] + [i]. + public static unsafe void Add(ReadOnlySpan x, ReadOnlySpan y, Span destination) => + InvokeSpanSpanIntoSpan(x, y, destination); + + /// Computes the element-wise result of: + . + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = [i] + . + public static void Add(ReadOnlySpan x, float y, Span destination) => + InvokeSpanScalarIntoSpan(x, y, destination); + + /// Computes the element-wise result of: - . + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = [i] - [i]. + public static void Subtract(ReadOnlySpan x, ReadOnlySpan y, Span destination) => + InvokeSpanSpanIntoSpan(x, y, destination); + + /// Computes the element-wise result of: - . + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = [i] - . + public static void Subtract(ReadOnlySpan x, float y, Span destination) => + InvokeSpanScalarIntoSpan(x, y, destination); + + /// Computes the element-wise result of: * . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = [i] * . + public static void Multiply(ReadOnlySpan x, ReadOnlySpan y, Span destination) => + InvokeSpanSpanIntoSpan(x, y, destination); + + /// Computes the element-wise result of: * . + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// + /// This method effectively does [i] = [i] * . + /// This method corresponds to the scal method defined by BLAS1. + /// + public static void Multiply(ReadOnlySpan x, float y, Span destination) => + InvokeSpanScalarIntoSpan(x, y, destination); + + /// Computes the element-wise result of: / . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = [i] / . + public static void Divide(ReadOnlySpan x, ReadOnlySpan y, Span destination) => + InvokeSpanSpanIntoSpan(x, y, destination); + + /// Computes the element-wise result of: / . + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = [i] / . + public static void Divide(ReadOnlySpan x, float y, Span destination) => + InvokeSpanScalarIntoSpan(x, y, destination); + + /// Computes the element-wise result of: -. + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = -[i]. + public static void Negate(ReadOnlySpan x, Span destination) => + InvokeSpanIntoSpan(x, destination); + + /// Computes the element-wise result of: ( + ) * . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The third tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = ([i] + [i]) * [i]. + public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan multiplier, Span destination) => + InvokeSpanSpanSpanIntoSpan(x, y, multiplier, destination); + + /// Computes the element-wise result of: ( + ) * . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The third tensor, represented as a scalar. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = ([i] + [i]) * . + public static void AddMultiply(ReadOnlySpan x, ReadOnlySpan y, float multiplier, Span destination) => + InvokeSpanSpanScalarIntoSpan(x, y, multiplier, destination); + + /// Computes the element-wise result of: ( + ) * . + /// The first tensor, represented as a span. + /// The second tensor, represented as a scalar. + /// The third tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = ([i] + ) * [i]. + public static void AddMultiply(ReadOnlySpan x, float y, ReadOnlySpan multiplier, Span destination) => + InvokeSpanScalarSpanIntoSpan(x, y, multiplier, destination); + + /// Computes the element-wise result of: ( * ) + . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The third tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = ([i] * [i]) + [i]. + public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan addend, Span destination) => + InvokeSpanSpanSpanIntoSpan(x, y, addend, destination); + + /// Computes the element-wise result of: ( * ) + . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The third tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// + /// This method effectively does [i] = ([i] * [i]) + . + /// This method corresponds to the axpy method defined by BLAS1. + /// + public static void MultiplyAdd(ReadOnlySpan x, ReadOnlySpan y, float addend, Span destination) => + InvokeSpanSpanScalarIntoSpan(x, y, addend, destination); + + /// Computes the element-wise result of: ( * ) + . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The third tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = ([i] * ) + [i]. + public static void MultiplyAdd(ReadOnlySpan x, float y, ReadOnlySpan addend, Span destination) => + InvokeSpanScalarSpanIntoSpan(x, y, addend, destination); + + /// Computes the element-wise result of: pow(e, ). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = .Exp([i]). + public static void Exp(ReadOnlySpan x, Span destination) + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Exp(x[i]); + } + } + + /// Computes the element-wise result of: ln(). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = .Log([i]). + public static void Log(ReadOnlySpan x, Span destination) + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Log(x[i]); + } + } + + /// Computes the element-wise result of: cosh(). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = .Cosh([i]). + public static void Cosh(ReadOnlySpan x, Span destination) + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Cosh(x[i]); + } + } + + /// Computes the element-wise result of: sinh(). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = .Sinh([i]). + public static void Sinh(ReadOnlySpan x, Span destination) + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Sinh(x[i]); + } + } + + /// Computes the element-wise result of: tanh(). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = .Tanh([i]). + public static void Tanh(ReadOnlySpan x, Span destination) + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Tanh(x[i]); + } + } + + /// Computes the cosine similarity between two non-zero vectors. + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The cosine similarity between the two vectors. + /// Length of '' must be same as length of ''. + /// '' and '' must not be empty. + public static float CosineSimilarity(ReadOnlySpan x, ReadOnlySpan y) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + return CosineSimilarityCore(x, y); + } + + /// + /// Compute the distance between two points in Euclidean space. + /// + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The Euclidean distance. + /// Length of '' must be same as length of ''. + /// '' and '' must not be empty. + public static float Distance(ReadOnlySpan x, ReadOnlySpan y) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + return MathF.Sqrt(Aggregate(0f, x, y)); + } + + /// + /// A mathematical operation that takes two vectors and returns a scalar. + /// + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The dot product. + /// Length of '' must be same as length of ''. + public static float Dot(ReadOnlySpan x, ReadOnlySpan y) // BLAS1: dot + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + return Aggregate(0f, x, y); + } + + /// + /// A mathematical operation that takes a vector and returns the L2 norm. + /// + /// The first tensor, represented as a span. + /// The L2 norm. + public static float L2Normalize(ReadOnlySpan x) // BLAS1: nrm2 + { + return MathF.Sqrt(Aggregate(0f, x)); + } + + /// + /// A function that takes a collection of real numbers and returns a probability distribution. + /// + /// The first tensor, represented as a span. + /// The destination tensor. + /// Destination is too short. + /// '' must not be empty. + public static void SoftMax(ReadOnlySpan x, Span destination) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + float expSum = 0f; + + for (int i = 0; i < x.Length; i++) + { + expSum += MathF.Pow((float)Math.E, x[i]); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Exp(x[i]) / expSum; + } + } + + /// + /// A function that takes a real number and returns a value between 0 and 1. + /// + /// The first tensor, represented as a span. + /// The destination tensor. + /// Destination is too short. + /// '' must not be empty. + public static void Sigmoid(ReadOnlySpan x, Span destination) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = 1f / (1 + MathF.Exp(-x[i])); + } + } + + /// Computes the maximum element in . + /// The tensor, represented as a span. + /// The maximum element in . + /// Length of '' must be greater than zero. + public static float Max(ReadOnlySpan x) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + float result = float.NegativeInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `maximum` function. + // It propagates NaN inputs back to the caller and + // otherwise returns the greater of the inputs. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + + if (current != result) + { + if (float.IsNaN(current)) + { + return current; + } + + if (result < current) + { + result = current; + } + } + else if (IsNegative(result)) + { + result = current; + } + } + + return result; + } + + /// Computes the minimum element in . + /// The tensor, represented as a span. + /// The minimum element in . + /// Length of '' must be greater than zero. + public static float Min(ReadOnlySpan x) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + float result = float.PositiveInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `minimum` function + // It propagates NaN inputs back to the caller and + // otherwise returns the lesser of the inputs. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + + if (current != result) + { + if (float.IsNaN(current)) + { + return current; + } + + if (current < result) + { + result = current; + } + } + else if (IsNegative(current)) + { + result = current; + } + } + + return result; + } + + /// Computes the maximum magnitude of any element in . + /// The tensor, represented as a span. + /// The maximum magnitude of any element in . + /// Length of '' must be greater than zero. + public static float MaxMagnitude(ReadOnlySpan x) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + float result = float.NegativeInfinity; + float resultMag = float.NegativeInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `maximumMagnitude` function. + // It propagates NaN inputs back to the caller and + // otherwise returns the input with a greater magnitude. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + float currentMag = Math.Abs(current); + + if (currentMag != resultMag) + { + if (float.IsNaN(currentMag)) + { + return currentMag; + } + + if (resultMag < currentMag) + { + result = current; + resultMag = currentMag; + } + } + else if (IsNegative(result)) + { + result = current; + resultMag = currentMag; + } + } + + return resultMag; + } + + /// Computes the minimum magnitude of any element in . + /// The tensor, represented as a span. + /// The minimum magnitude of any element in . + /// Length of '' must be greater than zero. + public static float MinMagnitude(ReadOnlySpan x) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + float resultMag = float.PositiveInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `minimumMagnitude` function. + // It propagates NaN inputs back to the caller and + // otherwise returns the input with a lesser magnitude. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + float currentMag = Math.Abs(current); + + if (currentMag != resultMag) + { + if (float.IsNaN(currentMag)) + { + return currentMag; + } + + if (currentMag < resultMag) + { + resultMag = currentMag; + } + } + else if (IsNegative(current)) + { + resultMag = currentMag; + } + } + + return resultMag; + } + + /// Computes the index of the maximum element in . + /// The tensor, represented as a span. + /// The index of the maximum element in , or -1 if is empty. + public static unsafe int IndexOfMax(ReadOnlySpan x) + { + int result = -1; + + if (!x.IsEmpty) + { + float max = float.NegativeInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `maximum` function. + // It propagates NaN inputs back to the caller and + // otherwise returns the greater of the inputs. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + + if (current != max) + { + if (float.IsNaN(current)) + { + return i; + } + + if (max < current) + { + result = i; + max = current; + } + } + else if (IsNegative(max) && !IsNegative(current)) + { + result = i; + max = current; + } + } + } + + return result; + } + + /// Computes the index of the minimum element in . + /// The tensor, represented as a span. + /// The index of the minimum element in , or -1 if is empty. + public static unsafe int IndexOfMin(ReadOnlySpan x) + { + int result = -1; + + if (!x.IsEmpty) + { + float min = float.PositiveInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `minimum` function. + // It propagates NaN inputs back to the caller and + // otherwise returns the lesser of the inputs. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + + if (current != min) + { + if (float.IsNaN(current)) + { + return i; + } + + if (current < min) + { + result = i; + min = current; + } + } + else if (IsNegative(current) && !IsNegative(min)) + { + result = i; + min = current; + } + } + } + + return result; + } + + /// Computes the index of the element in with the maximum magnitude. + /// The tensor, represented as a span. + /// The index of the element with the maximum magnitude, or -1 if is empty. + /// This method corresponds to the iamax method defined by BLAS1. + public static unsafe int IndexOfMaxMagnitude(ReadOnlySpan x) + { + int result = -1; + + if (!x.IsEmpty) + { + float max = float.NegativeInfinity; + float maxMag = float.NegativeInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `maximumMagnitude` function. + // It propagates NaN inputs back to the caller and + // otherwise returns the input with a greater magnitude. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + float currentMag = Math.Abs(current); + + if (currentMag != maxMag) + { + if (float.IsNaN(currentMag)) + { + return i; + } + + if (maxMag < currentMag) + { + result = i; + max = current; + maxMag = currentMag; + } + } + else if (IsNegative(max) && !IsNegative(current)) + { + result = i; + max = current; + maxMag = currentMag; + } + } + } + + return result; + } + + /// Computes the index of the element in with the minimum magnitude. + /// The tensor, represented as a span. + /// The index of the element with the minimum magnitude, or -1 if is empty. + public static unsafe int IndexOfMinMagnitude(ReadOnlySpan x) + { + int result = -1; + + if (!x.IsEmpty) + { + float min = float.PositiveInfinity; + float minMag = float.PositiveInfinity; + + for (int i = 0; i < x.Length; i++) + { + // This matches the IEEE 754:2019 `minimumMagnitude` function + // It propagates NaN inputs back to the caller and + // otherwise returns the input with a lesser magnitude. + // It treats +0 as greater than -0 as per the specification. + + float current = x[i]; + float currentMag = Math.Abs(current); + + if (currentMag != minMag) + { + if (float.IsNaN(currentMag)) + { + return i; + } + + if (currentMag < minMag) + { + result = i; + min = current; + minMag = currentMag; + } + } + else if (IsNegative(current) && !IsNegative(min)) + { + result = i; + min = current; + minMag = currentMag; + } + } + } + + return result; + } + + /// Computes the sum of all elements in . + /// The tensor, represented as a span. + /// The result of adding all elements in , or zero if is empty. + public static float Sum(ReadOnlySpan x) => + Aggregate(0f, x); + + /// Computes the sum of the squares of every element in . + /// The tensor, represented as a span. + /// The result of adding every element in multiplied by itself, or zero if is empty. + /// This method effectively does .Sum(.Multiply(, )). + public static float SumOfSquares(ReadOnlySpan x) => + Aggregate(0f, x); + + /// Computes the sum of the absolute values of every element in . + /// The tensor, represented as a span. + /// The result of adding the absolute value of every element in , or zero if is empty. + /// + /// This method effectively does .Sum(.Abs()). + /// This method corresponds to the asum method defined by BLAS1. + /// + public static float SumOfMagnitudes(ReadOnlySpan x) => + Aggregate(0f, x); + + /// Computes the product of all elements in . + /// The tensor, represented as a span. + /// The result of multiplying all elements in . + /// Length of '' must be greater than zero. + public static float Product(ReadOnlySpan x) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + return Aggregate(1.0f, x); + } + + /// Computes the product of the element-wise result of: + . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The result of multiplying the element-wise additions of the elements in each tensor. + /// Length of both input spans must be greater than zero. + /// and must have the same length. + /// This method effectively does .Product(.Add(, )). + public static float ProductOfSums(ReadOnlySpan x, ReadOnlySpan y) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + return Aggregate(1.0f, x, y); + } + + /// Computes the product of the element-wise result of: - . + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The result of multiplying the element-wise subtraction of the elements in the second tensor from the first tensor. + /// Length of both input spans must be greater than zero. + /// and must have the same length. + /// This method effectively does .Product(.Subtract(, )). + public static float ProductOfDifferences(ReadOnlySpan x, ReadOnlySpan y) + { + if (x.IsEmpty) + { + ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); + } + + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + return Aggregate(1.0f, x, y); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs new file mode 100644 index 00000000000000..4f40aa31494c97 --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs @@ -0,0 +1,1263 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + /// + /// Copies to , converting each + /// value to its nearest representable half-precision floating-point value. + /// + /// The source span from which to copy values. + /// The destination span into which the converted values should be written. + /// Destination is too short. + public static void ConvertToHalf(ReadOnlySpan source, Span destination) + { + if (source.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < source.Length; i++) + { + destination[i] = (Half)source[i]; + } + } + + /// + /// Copies to , converting each half-precision + /// floating-point value to its nearest representable value. + /// + /// The source span from which to copy values. + /// The destination span into which the converted values should be written. + /// Destination is too short. + public static void ConvertToSingle(ReadOnlySpan source, Span destination) + { + if (source.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < source.Length; i++) + { + destination[i] = (float)source[i]; + } + } + + private static bool IsNegative(float f) => float.IsNegative(f); + + private static float CosineSimilarityCore(ReadOnlySpan x, ReadOnlySpan y) + { + // Compute the same as: + // TensorPrimitives.Dot(x, y) / (Math.Sqrt(TensorPrimitives.SumOfSquares(x)) * Math.Sqrt(TensorPrimitives.SumOfSquares(y))) + // but only looping over each span once. + + float dotProduct = 0f; + float xSumOfSquares = 0f; + float ySumOfSquares = 0f; + + int i = 0; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated && x.Length >= Vector512.Count) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + Vector512 dotProductVector = Vector512.Zero; + Vector512 xSumOfSquaresVector = Vector512.Zero; + Vector512 ySumOfSquaresVector = Vector512.Zero; + + // Process vectors, summing their dot products and squares, as long as there's a vector's worth remaining. + int oneVectorFromEnd = x.Length - Vector512.Count; + do + { + Vector512 xVec = Vector512.LoadUnsafe(ref xRef, (uint)i); + Vector512 yVec = Vector512.LoadUnsafe(ref yRef, (uint)i); + + dotProductVector += xVec * yVec; + xSumOfSquaresVector += xVec * xVec; + ySumOfSquaresVector += yVec * yVec; + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Sum the vector lanes into the scalar result. + dotProduct += Vector512.Sum(dotProductVector); + xSumOfSquares += Vector512.Sum(xSumOfSquaresVector); + ySumOfSquares += Vector512.Sum(ySumOfSquaresVector); + } + else +#endif + if (Vector256.IsHardwareAccelerated && x.Length >= Vector256.Count) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + Vector256 dotProductVector = Vector256.Zero; + Vector256 xSumOfSquaresVector = Vector256.Zero; + Vector256 ySumOfSquaresVector = Vector256.Zero; + + // Process vectors, summing their dot products and squares, as long as there's a vector's worth remaining. + int oneVectorFromEnd = x.Length - Vector256.Count; + do + { + Vector256 xVec = Vector256.LoadUnsafe(ref xRef, (uint)i); + Vector256 yVec = Vector256.LoadUnsafe(ref yRef, (uint)i); + + dotProductVector += xVec * yVec; + xSumOfSquaresVector += xVec * xVec; + ySumOfSquaresVector += yVec * yVec; + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Sum the vector lanes into the scalar result. + dotProduct += Vector256.Sum(dotProductVector); + xSumOfSquares += Vector256.Sum(xSumOfSquaresVector); + ySumOfSquares += Vector256.Sum(ySumOfSquaresVector); + } + else if (Vector128.IsHardwareAccelerated && x.Length >= Vector128.Count) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + Vector128 dotProductVector = Vector128.Zero; + Vector128 xSumOfSquaresVector = Vector128.Zero; + Vector128 ySumOfSquaresVector = Vector128.Zero; + + // Process vectors, summing their dot products and squares, as long as there's a vector's worth remaining. + int oneVectorFromEnd = x.Length - Vector128.Count; + do + { + Vector128 xVec = Vector128.LoadUnsafe(ref xRef, (uint)i); + Vector128 yVec = Vector128.LoadUnsafe(ref yRef, (uint)i); + + dotProductVector += xVec * yVec; + xSumOfSquaresVector += xVec * xVec; + ySumOfSquaresVector += yVec * yVec; + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Sum the vector lanes into the scalar result. + dotProduct += Vector128.Sum(dotProductVector); + xSumOfSquares += Vector128.Sum(xSumOfSquaresVector); + ySumOfSquares += Vector128.Sum(ySumOfSquaresVector); + } + + // Process any remaining elements past the last vector. + for (; (uint)i < (uint)x.Length; i++) + { + dotProduct += x[i] * y[i]; + xSumOfSquares += x[i] * x[i]; + ySumOfSquares += y[i] * y[i]; + } + + // Sum(X * Y) / (|X| * |Y|) + return dotProduct / (MathF.Sqrt(xSumOfSquares) * MathF.Sqrt(ySumOfSquares)); + } + + private static float Aggregate( + float identityValue, ReadOnlySpan x) + where TLoad : IUnaryOperator + where TAggregate : IBinaryOperator + { + // Initialize the result to the identity value + float result = identityValue; + int i = 0; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated && x.Length >= Vector512.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + + // Load the first vector as the initial set of results + Vector512 resultVector = TLoad.Invoke(Vector512.LoadUnsafe(ref xRef, 0)); + int oneVectorFromEnd = x.Length - Vector512.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector512.Count; + do + { + resultVector = TAggregate.Invoke(resultVector, TLoad.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i))); + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + result = TAggregate.Invoke(result, TAggregate.Invoke(resultVector)); + } + else +#endif + if (Vector256.IsHardwareAccelerated && x.Length >= Vector256.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + + // Load the first vector as the initial set of results + Vector256 resultVector = TLoad.Invoke(Vector256.LoadUnsafe(ref xRef, 0)); + int oneVectorFromEnd = x.Length - Vector256.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector256.Count; + do + { + resultVector = TAggregate.Invoke(resultVector, TLoad.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i))); + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + result = TAggregate.Invoke(result, TAggregate.Invoke(resultVector)); + } + else if (Vector128.IsHardwareAccelerated && x.Length >= Vector128.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + + // Load the first vector as the initial set of results + Vector128 resultVector = TLoad.Invoke(Vector128.LoadUnsafe(ref xRef, 0)); + int oneVectorFromEnd = x.Length - Vector128.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector128.Count; + do + { + resultVector = TAggregate.Invoke(resultVector, TLoad.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i))); + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + result = TAggregate.Invoke(result, TAggregate.Invoke(resultVector)); + } + + // Aggregate the remaining items in the input span. + for (; (uint)i < (uint)x.Length; i++) + { + result = TAggregate.Invoke(result, TLoad.Invoke(x[i])); + } + + return result; + } + + private static float Aggregate( + float identityValue, ReadOnlySpan x, ReadOnlySpan y) + where TBinary : IBinaryOperator + where TAggregate : IBinaryOperator + { + // Initialize the result to the identity value + float result = identityValue; + int i = 0; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated && x.Length >= Vector512.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + // Load the first vector as the initial set of results + Vector512 resultVector = TBinary.Invoke(Vector512.LoadUnsafe(ref xRef, 0), Vector512.LoadUnsafe(ref yRef, 0)); + int oneVectorFromEnd = x.Length - Vector512.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector512.Count; + do + { + resultVector = TAggregate.Invoke(resultVector, TBinary.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i), Vector512.LoadUnsafe(ref yRef, (uint)i))); + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + result = TAggregate.Invoke(result, TAggregate.Invoke(resultVector)); + } + else +#endif + if (Vector256.IsHardwareAccelerated && x.Length >= Vector256.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + // Load the first vector as the initial set of results + Vector256 resultVector = TBinary.Invoke(Vector256.LoadUnsafe(ref xRef, 0), Vector256.LoadUnsafe(ref yRef, 0)); + int oneVectorFromEnd = x.Length - Vector256.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector256.Count; + do + { + resultVector = TAggregate.Invoke(resultVector, TBinary.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i), Vector256.LoadUnsafe(ref yRef, (uint)i))); + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + result = TAggregate.Invoke(result, TAggregate.Invoke(resultVector)); + } + else if (Vector128.IsHardwareAccelerated && x.Length >= Vector128.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + // Load the first vector as the initial set of results + Vector128 resultVector = TBinary.Invoke(Vector128.LoadUnsafe(ref xRef, 0), Vector128.LoadUnsafe(ref yRef, 0)); + int oneVectorFromEnd = x.Length - Vector128.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector128.Count; + do + { + resultVector = TAggregate.Invoke(resultVector, TBinary.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i), Vector128.LoadUnsafe(ref yRef, (uint)i))); + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + result = TAggregate.Invoke(result, TAggregate.Invoke(resultVector)); + } + + // Aggregate the remaining items in the input span. + for (; (uint)i < (uint)x.Length; i++) + { + result = TAggregate.Invoke(result, TBinary.Invoke(x[i], y[i])); + } + + return result; + } + + private static unsafe void InvokeSpanIntoSpan( + ReadOnlySpan x, Span destination) + where TUnaryOperator : IUnaryOperator + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector512.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TUnaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector512.Count); + TUnaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } +#endif + + if (Vector256.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector256.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TUnaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector256.Count); + TUnaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + if (Vector128.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector128.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TUnaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector128.Count); + TUnaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = TUnaryOperator.Invoke(Unsafe.Add(ref xRef, i)); + + i++; + } + } + + private static unsafe void InvokeSpanSpanIntoSpan( + ReadOnlySpan x, ReadOnlySpan y, Span destination) + where TBinaryOperator : IBinaryOperator + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector512.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TBinaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i), + Vector512.LoadUnsafe(ref yRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector512.Count); + TBinaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, lastVectorIndex), + Vector512.LoadUnsafe(ref yRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } +#endif + + if (Vector256.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector256.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TBinaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i), + Vector256.LoadUnsafe(ref yRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector256.Count); + TBinaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, lastVectorIndex), + Vector256.LoadUnsafe(ref yRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + if (Vector128.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector128.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TBinaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i), + Vector128.LoadUnsafe(ref yRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector128.Count); + TBinaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, lastVectorIndex), + Vector128.LoadUnsafe(ref yRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = TBinaryOperator.Invoke(Unsafe.Add(ref xRef, i), + Unsafe.Add(ref yRef, i)); + + i++; + } + } + + private static unsafe void InvokeSpanScalarIntoSpan( + ReadOnlySpan x, float y, Span destination) + where TBinaryOperator : IBinaryOperator + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector512.Count; + if (i <= oneVectorFromEnd) + { + Vector512 yVec = Vector512.Create(y); + + // Loop handling one vector at a time. + do + { + TBinaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i), + yVec).StoreUnsafe(ref dRef, (uint)i); + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector512.Count); + TBinaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, lastVectorIndex), + yVec).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } +#endif + + if (Vector256.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector256.Count; + if (i <= oneVectorFromEnd) + { + Vector256 yVec = Vector256.Create(y); + + // Loop handling one vector at a time. + do + { + TBinaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i), + yVec).StoreUnsafe(ref dRef, (uint)i); + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector256.Count); + TBinaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, lastVectorIndex), + yVec).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + if (Vector128.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector128.Count; + if (i <= oneVectorFromEnd) + { + Vector128 yVec = Vector128.Create(y); + + // Loop handling one vector at a time. + do + { + TBinaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i), + yVec).StoreUnsafe(ref dRef, (uint)i); + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector128.Count); + TBinaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, lastVectorIndex), + yVec).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = TBinaryOperator.Invoke(Unsafe.Add(ref xRef, i), + y); + + i++; + } + } + + private static unsafe void InvokeSpanSpanSpanIntoSpan( + ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan z, Span destination) + where TTernaryOperator : ITernaryOperator + { + if (x.Length != y.Length || x.Length != z.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + ref float zRef = ref MemoryMarshal.GetReference(z); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector512.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i), + Vector512.LoadUnsafe(ref yRef, (uint)i), + Vector512.LoadUnsafe(ref zRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector512.Count); + TTernaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, lastVectorIndex), + Vector512.LoadUnsafe(ref yRef, lastVectorIndex), + Vector512.LoadUnsafe(ref zRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } +#endif + + if (Vector256.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector256.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i), + Vector256.LoadUnsafe(ref yRef, (uint)i), + Vector256.LoadUnsafe(ref zRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector256.Count); + TTernaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, lastVectorIndex), + Vector256.LoadUnsafe(ref yRef, lastVectorIndex), + Vector256.LoadUnsafe(ref zRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + if (Vector128.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector128.Count; + if (i <= oneVectorFromEnd) + { + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i), + Vector128.LoadUnsafe(ref yRef, (uint)i), + Vector128.LoadUnsafe(ref zRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector128.Count); + TTernaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, lastVectorIndex), + Vector128.LoadUnsafe(ref yRef, lastVectorIndex), + Vector128.LoadUnsafe(ref zRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = TTernaryOperator.Invoke(Unsafe.Add(ref xRef, i), + Unsafe.Add(ref yRef, i), + Unsafe.Add(ref zRef, i)); + + i++; + } + } + + private static unsafe void InvokeSpanSpanScalarIntoSpan( + ReadOnlySpan x, ReadOnlySpan y, float z, Span destination) + where TTernaryOperator : ITernaryOperator + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector512.Count; + if (i <= oneVectorFromEnd) + { + Vector512 zVec = Vector512.Create(z); + + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i), + Vector512.LoadUnsafe(ref yRef, (uint)i), + zVec).StoreUnsafe(ref dRef, (uint)i); + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector512.Count); + TTernaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, lastVectorIndex), + Vector512.LoadUnsafe(ref yRef, lastVectorIndex), + zVec).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } +#endif + + if (Vector256.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector256.Count; + if (i <= oneVectorFromEnd) + { + Vector256 zVec = Vector256.Create(z); + + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i), + Vector256.LoadUnsafe(ref yRef, (uint)i), + zVec).StoreUnsafe(ref dRef, (uint)i); + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector256.Count); + TTernaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, lastVectorIndex), + Vector256.LoadUnsafe(ref yRef, lastVectorIndex), + zVec).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + if (Vector128.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector128.Count; + if (i <= oneVectorFromEnd) + { + Vector128 zVec = Vector128.Create(z); + + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i), + Vector128.LoadUnsafe(ref yRef, (uint)i), + zVec).StoreUnsafe(ref dRef, (uint)i); + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector128.Count); + TTernaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, lastVectorIndex), + Vector128.LoadUnsafe(ref yRef, lastVectorIndex), + zVec).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = TTernaryOperator.Invoke(Unsafe.Add(ref xRef, i), + Unsafe.Add(ref yRef, i), + z); + + i++; + } + } + + private static unsafe void InvokeSpanScalarSpanIntoSpan( + ReadOnlySpan x, float y, ReadOnlySpan z, Span destination) + where TTernaryOperator : ITernaryOperator + { + if (x.Length != z.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float zRef = ref MemoryMarshal.GetReference(z); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector512.Count; + if (i <= oneVectorFromEnd) + { + Vector512 yVec = Vector512.Create(y); + + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, (uint)i), + yVec, + Vector512.LoadUnsafe(ref zRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector512.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector512.Count); + TTernaryOperator.Invoke(Vector512.LoadUnsafe(ref xRef, lastVectorIndex), + yVec, + Vector512.LoadUnsafe(ref zRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } +#endif + + if (Vector256.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector256.Count; + if (i <= oneVectorFromEnd) + { + Vector256 yVec = Vector256.Create(y); + + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, (uint)i), + yVec, + Vector256.LoadUnsafe(ref zRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector256.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector256.Count); + TTernaryOperator.Invoke(Vector256.LoadUnsafe(ref xRef, lastVectorIndex), + yVec, + Vector256.LoadUnsafe(ref zRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + if (Vector128.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector128.Count; + if (i <= oneVectorFromEnd) + { + Vector128 yVec = Vector128.Create(y); + + // Loop handling one vector at a time. + do + { + TTernaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, (uint)i), + yVec, + Vector128.LoadUnsafe(ref zRef, (uint)i)).StoreUnsafe(ref dRef, (uint)i); + + i += Vector128.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + uint lastVectorIndex = (uint)(x.Length - Vector128.Count); + TTernaryOperator.Invoke(Vector128.LoadUnsafe(ref xRef, lastVectorIndex), + yVec, + Vector128.LoadUnsafe(ref zRef, lastVectorIndex)).StoreUnsafe(ref dRef, lastVectorIndex); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = TTernaryOperator.Invoke(Unsafe.Add(ref xRef, i), + y, + Unsafe.Add(ref zRef, i)); + + i++; + } + } + + private readonly struct AddOperator : IBinaryOperator + { + public static float Invoke(float x, float y) => x + y; + public static Vector128 Invoke(Vector128 x, Vector128 y) => x + y; + public static Vector256 Invoke(Vector256 x, Vector256 y) => x + y; +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x, Vector512 y) => x + y; +#endif + + public static float Invoke(Vector128 x) => Vector128.Sum(x); + public static float Invoke(Vector256 x) => Vector256.Sum(x); +#if NET8_0_OR_GREATER + public static float Invoke(Vector512 x) => Vector512.Sum(x); +#endif + } + + private readonly struct SubtractOperator : IBinaryOperator + { + public static float Invoke(float x, float y) => x - y; + public static Vector128 Invoke(Vector128 x, Vector128 y) => x - y; + public static Vector256 Invoke(Vector256 x, Vector256 y) => x - y; +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x, Vector512 y) => x - y; +#endif + + public static float Invoke(Vector128 x) => throw new NotSupportedException(); + public static float Invoke(Vector256 x) => throw new NotSupportedException(); +#if NET8_0_OR_GREATER + public static float Invoke(Vector512 x) => throw new NotSupportedException(); +#endif + } + + private readonly struct SubtractSquaredOperator : IBinaryOperator + { + public static float Invoke(float x, float y) + { + float tmp = x - y; + return tmp * tmp; + } + + public static Vector128 Invoke(Vector128 x, Vector128 y) + { + Vector128 tmp = x - y; + return tmp * tmp; + } + + public static Vector256 Invoke(Vector256 x, Vector256 y) + { + Vector256 tmp = x - y; + return tmp * tmp; + } + +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x, Vector512 y) + { + Vector512 tmp = x - y; + return tmp * tmp; + } +#endif + + public static float Invoke(Vector128 x) => throw new NotSupportedException(); + public static float Invoke(Vector256 x) => throw new NotSupportedException(); +#if NET8_0_OR_GREATER + public static float Invoke(Vector512 x) => throw new NotSupportedException(); +#endif + } + + private readonly struct MultiplyOperator : IBinaryOperator + { + public static float Invoke(float x, float y) => x * y; + public static Vector128 Invoke(Vector128 x, Vector128 y) => x * y; + public static Vector256 Invoke(Vector256 x, Vector256 y) => x * y; +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x, Vector512 y) => x * y; +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Invoke(Vector128 x) + { + float f = x[0]; + for (int i = 1; i < Vector128.Count; i++) + { + f *= x[i]; + } + return f; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Invoke(Vector256 x) + { + float f = x[0]; + for (int i = 1; i < Vector256.Count; i++) + { + f *= x[i]; + } + return f; + } + +#if NET8_0_OR_GREATER + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Invoke(Vector512 x) + { + float f = x[0]; + for (int i = 1; i < Vector512.Count; i++) + { + f *= x[i]; + } + return f; + } +#endif + } + + private readonly struct DivideOperator : IBinaryOperator + { + public static float Invoke(float x, float y) => x / y; + public static Vector128 Invoke(Vector128 x, Vector128 y) => x / y; + public static Vector256 Invoke(Vector256 x, Vector256 y) => x / y; +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x, Vector512 y) => x / y; +#endif + + public static float Invoke(Vector128 x) => throw new NotSupportedException(); + public static float Invoke(Vector256 x) => throw new NotSupportedException(); +#if NET8_0_OR_GREATER + public static float Invoke(Vector512 x) => throw new NotSupportedException(); +#endif + } + + private readonly struct NegateOperator : IUnaryOperator + { + public static float Invoke(float x) => -x; + public static Vector128 Invoke(Vector128 x) => -x; + public static Vector256 Invoke(Vector256 x) => -x; + public static Vector512 Invoke(Vector512 x) => -x; + } + + private readonly struct AddMultiplyOperator : ITernaryOperator + { + public static float Invoke(float x, float y, float z) => (x + y) * z; + public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) => (x + y) * z; + public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) => (x + y) * z; + public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) => (x + y) * z; + } + + private readonly struct MultiplyAddOperator : ITernaryOperator + { + public static float Invoke(float x, float y, float z) => (x * y) + z; + public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) => (x * y) + z; + public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) => (x * y) + z; + public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) => (x * y) + z; + } + + private readonly struct LoadIdentity : IUnaryOperator + { + public static float Invoke(float x) => x; + public static Vector128 Invoke(Vector128 x) => x; + public static Vector256 Invoke(Vector256 x) => x; +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x) => x; +#endif + } + + private readonly struct LoadSquared : IUnaryOperator + { + public static float Invoke(float x) => x * x; + public static Vector128 Invoke(Vector128 x) => x * x; + public static Vector256 Invoke(Vector256 x) => x * x; +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x) => x * x; +#endif + } + + private readonly struct LoadAbsolute : IUnaryOperator + { + public static float Invoke(float x) => MathF.Abs(x); + + public static Vector128 Invoke(Vector128 x) + { + Vector128 raw = x.AsUInt32(); + Vector128 mask = Vector128.Create((uint)0x7FFFFFFF); + return (raw & mask).AsSingle(); + } + + public static Vector256 Invoke(Vector256 x) + { + Vector256 raw = x.AsUInt32(); + Vector256 mask = Vector256.Create((uint)0x7FFFFFFF); + return (raw & mask).AsSingle(); + } + +#if NET8_0_OR_GREATER + public static Vector512 Invoke(Vector512 x) + { + Vector512 raw = x.AsUInt32(); + Vector512 mask = Vector512.Create((uint)0x7FFFFFFF); + return (raw & mask).AsSingle(); + } +#endif + } + + private interface IUnaryOperator + { + static abstract float Invoke(float x); + static abstract Vector128 Invoke(Vector128 x); + static abstract Vector256 Invoke(Vector256 x); +#if NET8_0_OR_GREATER + static abstract Vector512 Invoke(Vector512 x); +#endif + } + + private interface IBinaryOperator + { + static abstract float Invoke(float x, float y); + + static abstract Vector128 Invoke(Vector128 x, Vector128 y); + static abstract float Invoke(Vector128 x); + static abstract Vector256 Invoke(Vector256 x, Vector256 y); + static abstract float Invoke(Vector256 x); +#if NET8_0_OR_GREATER + static abstract Vector512 Invoke(Vector512 x, Vector512 y); + static abstract float Invoke(Vector512 x); +#endif + } + + private interface ITernaryOperator + { + static abstract float Invoke(float x, float y, float z); + static abstract Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z); + static abstract Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z); +#if NET8_0_OR_GREATER + static abstract Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z); +#endif + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs new file mode 100644 index 00000000000000..134364708b8e5d --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs @@ -0,0 +1,596 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + private static unsafe bool IsNegative(float f) => *(int*)&f < 0; + + private static float CosineSimilarityCore(ReadOnlySpan x, ReadOnlySpan y) + { + // Compute the same as: + // TensorPrimitives.Dot(x, y) / (Math.Sqrt(TensorPrimitives.SumOfSquares(x)) * Math.Sqrt(TensorPrimitives.SumOfSquares(y))) + // but only looping over each span once. + + float dotProduct = 0f; + float xSumOfSquares = 0f; + float ySumOfSquares = 0f; + + int i = 0; + + if (Vector.IsHardwareAccelerated && x.Length >= Vector.Count) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + Vector dotProductVector = Vector.Zero; + Vector xSumOfSquaresVector = Vector.Zero; + Vector ySumOfSquaresVector = Vector.Zero; + + // Process vectors, summing their dot products and squares, as long as there's a vector's worth remaining. + int oneVectorFromEnd = x.Length - Vector.Count; + do + { + Vector xVec = AsVector(ref xRef, i); + Vector yVec = AsVector(ref yRef, i); + + dotProductVector += xVec * yVec; + xSumOfSquaresVector += xVec * xVec; + ySumOfSquaresVector += yVec * yVec; + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Sum the vector lanes into the scalar result. + for (int e = 0; e < Vector.Count; e++) + { + dotProduct += dotProductVector[e]; + xSumOfSquares += xSumOfSquaresVector[e]; + ySumOfSquares += ySumOfSquaresVector[e]; + } + } + + // Process any remaining elements past the last vector. + for (; (uint)i < (uint)x.Length; i++) + { + dotProduct += x[i] * y[i]; + xSumOfSquares += x[i] * x[i]; + ySumOfSquares += y[i] * y[i]; + } + + // Sum(X * Y) / (|X| * |Y|) + return dotProduct / (MathF.Sqrt(xSumOfSquares) * MathF.Sqrt(ySumOfSquares)); + } + + private static float Aggregate( + float identityValue, ReadOnlySpan x, TLoad load = default, TAggregate aggregate = default) + where TLoad : IUnaryOperator + where TAggregate : IBinaryOperator + { + // Initialize the result to the identity value + float result = identityValue; + int i = 0; + + if (Vector.IsHardwareAccelerated && x.Length >= Vector.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + + // Load the first vector as the initial set of results + Vector resultVector = load.Invoke(AsVector(ref xRef, 0)); + int oneVectorFromEnd = x.Length - Vector.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector.Count; + do + { + resultVector = aggregate.Invoke(resultVector, load.Invoke(AsVector(ref xRef, i))); + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + for (int f = 0; f < Vector.Count; f++) + { + result = aggregate.Invoke(result, resultVector[f]); + } + } + + // Aggregate the remaining items in the input span. + for (; (uint)i < (uint)x.Length; i++) + { + result = aggregate.Invoke(result, load.Invoke(x[i])); + } + + return result; + } + + private static float Aggregate( + float identityValue, ReadOnlySpan x, ReadOnlySpan y, TBinary binary = default, TAggregate aggregate = default) + where TBinary : IBinaryOperator + where TAggregate : IBinaryOperator + { + // Initialize the result to the identity value + float result = identityValue; + int i = 0; + + if (Vector.IsHardwareAccelerated && x.Length >= Vector.Count * 2) + { + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + + // Load the first vector as the initial set of results + Vector resultVector = binary.Invoke(AsVector(ref xRef, 0), AsVector(ref yRef, 0)); + int oneVectorFromEnd = x.Length - Vector.Count; + + // Aggregate additional vectors into the result as long as there's at + // least one full vector left to process. + i = Vector.Count; + do + { + resultVector = aggregate.Invoke(resultVector, binary.Invoke(AsVector(ref xRef, i), AsVector(ref yRef, i))); + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Aggregate the lanes in the vector back into the scalar result + for (int f = 0; f < Vector.Count; f++) + { + result = aggregate.Invoke(result, resultVector[f]); + } + } + + // Aggregate the remaining items in the input span. + for (; (uint)i < (uint)x.Length; i++) + { + result = aggregate.Invoke(result, binary.Invoke(x[i], y[i])); + } + + return result; + } + + private static void InvokeSpanIntoSpan( + ReadOnlySpan x, Span destination, TUnaryOperator op = default) + where TUnaryOperator : IUnaryOperator + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + + if (Vector.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector.Count; + if (oneVectorFromEnd >= 0) + { + // Loop handling one vector at a time. + do + { + AsVector(ref dRef, i) = op.Invoke(AsVector(ref xRef, i)); + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + int lastVectorIndex = x.Length - Vector.Count; + AsVector(ref dRef, lastVectorIndex) = op.Invoke(AsVector(ref xRef, lastVectorIndex)); + } + + return; + } + } + + // Loop handling one element at a time. + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = op.Invoke(Unsafe.Add(ref xRef, i)); + + i++; + } + } + + private static void InvokeSpanSpanIntoSpan( + ReadOnlySpan x, ReadOnlySpan y, Span destination, TBinaryOperator op = default) + where TBinaryOperator : IBinaryOperator + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + + if (Vector.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector.Count; + if (oneVectorFromEnd >= 0) + { + // Loop handling one vector at a time. + do + { + AsVector(ref dRef, i) = op.Invoke(AsVector(ref xRef, i), + AsVector(ref yRef, i)); + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + int lastVectorIndex = x.Length - Vector.Count; + AsVector(ref dRef, lastVectorIndex) = op.Invoke(AsVector(ref xRef, lastVectorIndex), + AsVector(ref yRef, lastVectorIndex)); + } + + return; + } + } + + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = op.Invoke(Unsafe.Add(ref xRef, i), + Unsafe.Add(ref yRef, i)); + + i++; + } + } + + private static void InvokeSpanScalarIntoSpan( + ReadOnlySpan x, float y, Span destination, TBinaryOperator op = default) + where TBinaryOperator : IBinaryOperator + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + + if (Vector.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector.Count; + if (oneVectorFromEnd >= 0) + { + // Loop handling one vector at a time. + Vector yVec = new(y); + do + { + AsVector(ref dRef, i) = op.Invoke(AsVector(ref xRef, i), + yVec); + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + int lastVectorIndex = x.Length - Vector.Count; + AsVector(ref dRef, lastVectorIndex) = op.Invoke(AsVector(ref xRef, lastVectorIndex), + yVec); + } + + return; + } + } + + // Loop handling one element at a time. + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = op.Invoke(Unsafe.Add(ref xRef, i), + y); + + i++; + } + } + + private static void InvokeSpanSpanSpanIntoSpan( + ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan z, Span destination, TTernaryOperator op = default) + where TTernaryOperator : ITernaryOperator + { + if (x.Length != y.Length || x.Length != z.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + ref float zRef = ref MemoryMarshal.GetReference(z); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + + if (Vector.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector.Count; + if (oneVectorFromEnd >= 0) + { + // Loop handling one vector at a time. + do + { + AsVector(ref dRef, i) = op.Invoke(AsVector(ref xRef, i), + AsVector(ref yRef, i), + AsVector(ref zRef, i)); + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + int lastVectorIndex = x.Length - Vector.Count; + AsVector(ref dRef, lastVectorIndex) = op.Invoke(AsVector(ref xRef, lastVectorIndex), + AsVector(ref yRef, lastVectorIndex), + AsVector(ref zRef, lastVectorIndex)); + } + + return; + } + } + + // Loop handling one element at a time. + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = op.Invoke(Unsafe.Add(ref xRef, i), + Unsafe.Add(ref yRef, i), + Unsafe.Add(ref zRef, i)); + + i++; + } + } + + private static void InvokeSpanSpanScalarIntoSpan( + ReadOnlySpan x, ReadOnlySpan y, float z, Span destination, TTernaryOperator op = default) + where TTernaryOperator : ITernaryOperator + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float yRef = ref MemoryMarshal.GetReference(y); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + + if (Vector.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector.Count; + if (oneVectorFromEnd >= 0) + { + Vector zVec = new(z); + + // Loop handling one vector at a time. + do + { + AsVector(ref dRef, i) = op.Invoke(AsVector(ref xRef, i), + AsVector(ref yRef, i), + zVec); + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + int lastVectorIndex = x.Length - Vector.Count; + AsVector(ref dRef, lastVectorIndex) = op.Invoke(AsVector(ref xRef, lastVectorIndex), + AsVector(ref yRef, lastVectorIndex), + zVec); + } + + return; + } + } + + // Loop handling one element at a time. + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = op.Invoke(Unsafe.Add(ref xRef, i), + Unsafe.Add(ref yRef, i), + z); + + i++; + } + } + + private static void InvokeSpanScalarSpanIntoSpan( + ReadOnlySpan x, float y, ReadOnlySpan z, Span destination, TTernaryOperator op = default) + where TTernaryOperator : ITernaryOperator + { + if (x.Length != z.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + ref float xRef = ref MemoryMarshal.GetReference(x); + ref float zRef = ref MemoryMarshal.GetReference(z); + ref float dRef = ref MemoryMarshal.GetReference(destination); + int i = 0, oneVectorFromEnd; + + if (Vector.IsHardwareAccelerated) + { + oneVectorFromEnd = x.Length - Vector.Count; + if (oneVectorFromEnd >= 0) + { + Vector yVec = new(y); + + // Loop handling one vector at a time. + do + { + AsVector(ref dRef, i) = op.Invoke(AsVector(ref xRef, i), + yVec, + AsVector(ref zRef, i)); + + i += Vector.Count; + } + while (i <= oneVectorFromEnd); + + // Handle any remaining elements with a final vector. + if (i != x.Length) + { + int lastVectorIndex = x.Length - Vector.Count; + AsVector(ref dRef, lastVectorIndex) = op.Invoke(AsVector(ref xRef, lastVectorIndex), + yVec, + AsVector(ref zRef, lastVectorIndex)); + } + + return; + } + } + + // Loop handling one element at a time. + while (i < x.Length) + { + Unsafe.Add(ref dRef, i) = op.Invoke(Unsafe.Add(ref xRef, i), + y, + Unsafe.Add(ref zRef, i)); + + i++; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref Vector AsVector(ref float start, int offset) => + ref Unsafe.As>( + ref Unsafe.Add(ref start, offset)); + + private readonly struct AddOperator : IBinaryOperator + { + public float Invoke(float x, float y) => x + y; + public Vector Invoke(Vector x, Vector y) => x + y; + } + + private readonly struct SubtractOperator : IBinaryOperator + { + public float Invoke(float x, float y) => x - y; + public Vector Invoke(Vector x, Vector y) => x - y; + } + + private readonly struct SubtractSquaredOperator : IBinaryOperator + { + public float Invoke(float x, float y) + { + float tmp = x - y; + return tmp * tmp; + } + + public Vector Invoke(Vector x, Vector y) + { + Vector tmp = x - y; + return tmp * tmp; + } + } + + private readonly struct MultiplyOperator : IBinaryOperator + { + public float Invoke(float x, float y) => x * y; + public Vector Invoke(Vector x, Vector y) => x * y; + } + + private readonly struct DivideOperator : IBinaryOperator + { + public float Invoke(float x, float y) => x / y; + public Vector Invoke(Vector x, Vector y) => x / y; + } + + private readonly struct NegateOperator : IUnaryOperator + { + public float Invoke(float x) => -x; + public Vector Invoke(Vector x) => -x; + } + + private readonly struct AddMultiplyOperator : ITernaryOperator + { + public float Invoke(float x, float y, float z) => (x + y) * z; + public Vector Invoke(Vector x, Vector y, Vector z) => (x + y) * z; + } + + private readonly struct MultiplyAddOperator : ITernaryOperator + { + public float Invoke(float x, float y, float z) => (x * y) + z; + public Vector Invoke(Vector x, Vector y, Vector z) => (x * y) + z; + } + + private readonly struct LoadIdentity : IUnaryOperator + { + public float Invoke(float x) => x; + public Vector Invoke(Vector x) => x; + } + + private readonly struct LoadSquared : IUnaryOperator + { + public float Invoke(float x) => x * x; + public Vector Invoke(Vector x) => x * x; + } + + private readonly struct LoadAbsolute : IUnaryOperator + { + public float Invoke(float x) => MathF.Abs(x); + + public Vector Invoke(Vector x) + { + Vector raw = Vector.AsVectorUInt32(x); + Vector mask = new Vector(0x7FFFFFFF); + return Vector.AsVectorSingle(raw & mask); + } + } + + private interface IUnaryOperator + { + float Invoke(float x); + Vector Invoke(Vector x); + } + + private interface IBinaryOperator + { + float Invoke(float x, float y); + Vector Invoke(Vector x, Vector y); + } + + private interface ITernaryOperator + { + float Invoke(float x, float y, float z); + Vector Invoke(Vector x, Vector y, Vector z); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs b/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs new file mode 100644 index 00000000000000..902b27787e856c --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +namespace System +{ + internal static class ThrowHelper + { + [DoesNotReturn] + public static void ThrowArgument_DestinationTooShort() => + throw new ArgumentException(SR.Argument_DestinationTooShort, "destination"); + + [DoesNotReturn] + public static void ThrowArgument_SpansMustHaveSameLength() => + throw new ArgumentException(SR.Argument_SpansMustHaveSameLength); + + [DoesNotReturn] + public static void ThrowArgument_SpansMustBeNonEmpty() => + throw new ArgumentException(SR.Argument_SpansMustBeNonEmpty); + } +} diff --git a/src/libraries/System.Numerics.Tensors/tests/NativeMemory.cs b/src/libraries/System.Numerics.Tensors/tests/NativeMemory.cs deleted file mode 100644 index b5c9ef8c2c2c92..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/NativeMemory.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Threading; - -namespace System.Numerics.Tensors.Tests -{ - public class NativeMemory : MemoryManager - { - private bool disposed = false; - private int refCount = 0; - private IntPtr memory; - private int length; - - public NativeMemory(IntPtr memory, int length) - { - this.memory = memory; - this.length = length; - } - - public unsafe NativeMemory(void* memory, int length) - { - this.memory = (IntPtr)memory; - this.length = length; - } - - ~NativeMemory() - { - Dispose(false); - } - - public static NativeMemory Allocate(int length) - { - // typically this would call into a native method appropriate for the platform - // or the constructors above would be used to wrap the native pointer - IntPtr memory = Marshal.AllocHGlobal(Marshal.SizeOf() * length); - return new NativeMemory(memory, length); - } - - public bool IsDisposed => disposed; - - public unsafe override Span GetSpan() => new Span((void*)memory, length); - - protected bool IsRetained => refCount > 0; - - public override MemoryHandle Pin(int elementIndex = 0) - { - unsafe - { - Retain(); - if ((uint)elementIndex > length) throw new ArgumentOutOfRangeException(nameof(elementIndex)); - void* pointer = Unsafe.Add((void*)memory, elementIndex); - return new MemoryHandle(pointer, default, this); - } - } - - public bool Release() - { - int newRefCount = Interlocked.Decrement(ref refCount); - - if (newRefCount < 0) - { - throw new InvalidOperationException("Unmatched Release/Retain"); - } - - return newRefCount != 0; - } - - public void Retain() - { - if (disposed) - { - throw new ObjectDisposedException(nameof(NativeMemory)); - } - - Interlocked.Increment(ref refCount); - } - - protected override void Dispose(bool disposing) - { - if (disposed) - { - return; - } - - // typically this would call into a native method appropriate for the platform - Marshal.FreeHGlobal(memory); - memory = IntPtr.Zero; - - disposed = true; - } - - protected override bool TryGetArray(out ArraySegment arraySegment) - { - // cannot expose managed array - arraySegment = default; - return false; - } - - public override void Unpin() - { - Release(); - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/tests/System.Numerics.Tensors.Tests.csproj b/src/libraries/System.Numerics.Tensors/tests/System.Numerics.Tensors.Tests.csproj index 042e4791b6a3d8..be4a103d7256ce 100644 --- a/src/libraries/System.Numerics.Tensors/tests/System.Numerics.Tensors.Tests.csproj +++ b/src/libraries/System.Numerics.Tensors/tests/System.Numerics.Tensors.Tests.csproj @@ -1,41 +1,21 @@ + - true $(NetCoreAppCurrent);$(NetFrameworkMinimum) + true + - - - True - True - TensorArithmetic.tt - - - - True - True - TensorOperations.tt - - - + - - - TextTemplatingFileGenerator - TensorArithmetic.cs - - - TextTemplatingFileGenerator - TensorOperations.cs - - + + + + - - - - + \ No newline at end of file diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorArithmetic.cs b/src/libraries/System.Numerics.Tensors/tests/TensorArithmetic.cs deleted file mode 100644 index 6dae2ec6854252..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorArithmetic.cs +++ /dev/null @@ -1,16165 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Numerics.Tensors -{ - internal interface ITensorArithmetic - { - T One { get; } - T Zero { get; } - void Add(Tensor left, Tensor right, Tensor result); - void Add(Tensor tensor, T scalar, Tensor result); - void And(Tensor left, Tensor right, Tensor result); - void And(Tensor tensor, T scalar, Tensor result); - void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result); - void Decrement(Tensor tensor, Tensor result); - void Divide(Tensor left, Tensor right, Tensor result); - void Divide(Tensor tensor, T scalar, Tensor result); - void Equals(Tensor left, Tensor right, Tensor result); - void GreaterThan(Tensor left, Tensor right, Tensor result); - void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result); - void Increment(Tensor tensor, Tensor result); - void LeftShift(Tensor tensor, int value, Tensor result); - void LessThan(Tensor left, Tensor right, Tensor result); - void LessThanOrEqual(Tensor left, Tensor right, Tensor result); - void Modulo(Tensor left, Tensor right, Tensor result); - void Modulo(Tensor tensor, T scalar, Tensor result); - void Multiply(Tensor left, Tensor right, Tensor result); - void Multiply(Tensor tensor, T scalar, Tensor result); - void NotEquals(Tensor left, Tensor right, Tensor result); - void Or(Tensor left, Tensor right, Tensor result); - void Or(Tensor tensor, T scalar, Tensor result); - void RightShift(Tensor tensor, int value, Tensor result); - void Subtract(Tensor left, Tensor right, Tensor result); - void Subtract(Tensor tensor, T scalar, Tensor result); - void UnaryMinus(Tensor tensor, Tensor result); - void UnaryPlus(Tensor tensor, Tensor result); - void Xor(Tensor left, Tensor right, Tensor result); - void Xor(Tensor tensor, T scalar, Tensor result); - } - - internal static class TensorArithmetic - { - public static ITensorArithmetic Instance => TensorArithmetic.GetArithmetic(); - } - - internal static class TensorArithmetic - { - public static ITensorArithmetic GetArithmetic() - { - if (typeof(T) == typeof(bool)) - { - return (ITensorArithmetic)new BoolArithmetic(); - } - else if (typeof(T) == typeof(byte)) - { - return (ITensorArithmetic)new ByteArithmetic(); - } - else if (typeof(T) == typeof(char)) - { - return (ITensorArithmetic)new CharArithmetic(); - } - else if (typeof(T) == typeof(decimal)) - { - return (ITensorArithmetic)new DecimalArithmetic(); - } - else if (typeof(T) == typeof(double)) - { - return (ITensorArithmetic)new DoubleArithmetic(); - } - else if (typeof(T) == typeof(float)) - { - return (ITensorArithmetic)new FloatArithmetic(); - } - else if (typeof(T) == typeof(int)) - { - return (ITensorArithmetic)new IntArithmetic(); - } - else if (typeof(T) == typeof(long)) - { - return (ITensorArithmetic)new LongArithmetic(); - } - else if (typeof(T) == typeof(sbyte)) - { - return (ITensorArithmetic)new SByteArithmetic(); - } - else if (typeof(T) == typeof(short)) - { - return (ITensorArithmetic)new ShortArithmetic(); - } - else if (typeof(T) == typeof(uint)) - { - return (ITensorArithmetic)new UIntArithmetic(); - } - else if (typeof(T) == typeof(ulong)) - { - return (ITensorArithmetic)new ULongArithmetic(); - } - else if (typeof(T) == typeof(ushort)) - { - return (ITensorArithmetic)new UShortArithmetic(); - } - return null; - } - } - - internal class BoolArithmetic : ITensorArithmetic - { - public bool One => true; - public bool Zero => false; - - public void Add(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Add(Tensor tensor, bool scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (bool)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, bool scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (bool)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - throw new NotSupportedException(); - } - public void Decrement(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Divide(Tensor tensor, bool scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Increment(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Modulo(Tensor tensor, bool scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Multiply(Tensor tensor, bool scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (bool)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, bool scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (bool)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Subtract(Tensor tensor, bool scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (bool)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, bool scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (bool)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Add(DenseTensor tensor, bool scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (bool)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (bool)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, bool scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (bool)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (bool)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Divide(DenseTensor tensor, bool scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Modulo(DenseTensor tensor, bool scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Multiply(DenseTensor tensor, bool scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (bool)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (bool)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, bool scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (bool)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (bool)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Subtract(DenseTensor tensor, bool scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (bool)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (bool)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, bool scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (bool)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (bool)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class ByteArithmetic : ITensorArithmetic - { - public byte One => 1; - public byte Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - byte sum = (byte)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (byte)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, byte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (byte)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - byte sum = (byte)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (byte)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, byte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (byte)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (byte)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class CharArithmetic : ITensorArithmetic - { - public char One => (char)1; - public char Zero => (char)0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - char sum = (char)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (char)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, char scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (char)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - char sum = (char)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (char)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, char scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (char)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (char)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class DecimalArithmetic : ITensorArithmetic - { - public decimal One => 1; - public decimal Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, decimal scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void And(Tensor tensor, decimal scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - decimal sum = (decimal)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (decimal)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, decimal scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, decimal scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, decimal scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Or(Tensor tensor, decimal scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, decimal scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (decimal)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Xor(Tensor tensor, decimal scalar, Tensor result) - { - throw new NotSupportedException(); - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, decimal scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void And(DenseTensor tensor, decimal scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - decimal sum = (decimal)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (decimal)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, decimal scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, decimal scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, decimal scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Or(DenseTensor tensor, decimal scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, decimal scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (decimal)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (decimal)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Xor(DenseTensor tensor, decimal scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - } - internal class DoubleArithmetic : ITensorArithmetic - { - public double One => 1.0; - public double Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, double scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void And(Tensor tensor, double scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - double sum = (double)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (double)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, double scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, double scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, double scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Or(Tensor tensor, double scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, double scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (double)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Xor(Tensor tensor, double scalar, Tensor result) - { - throw new NotSupportedException(); - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, double scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void And(DenseTensor tensor, double scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - double sum = (double)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (double)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, double scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, double scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, double scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Or(DenseTensor tensor, double scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, double scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (double)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (double)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Xor(DenseTensor tensor, double scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - } - internal class FloatArithmetic : ITensorArithmetic - { - public float One => 1.0f; - public float Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, float scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void And(Tensor tensor, float scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - float sum = (float)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (float)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, float scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, float scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, float scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Or(Tensor tensor, float scalar, Tensor result) - { - throw new NotSupportedException(); - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - throw new NotSupportedException(); - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, float scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (float)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - throw new NotSupportedException(); - } - public void Xor(Tensor tensor, float scalar, Tensor result) - { - throw new NotSupportedException(); - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, float scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void And(DenseTensor tensor, float scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - float sum = (float)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (float)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, float scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, float scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, float scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Or(DenseTensor tensor, float scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, float scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (float)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (float)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - throw new NotSupportedException(); - } - public void Xor(DenseTensor tensor, float scalar, DenseTensor result) - { - throw new NotSupportedException(); - } - } - internal class IntArithmetic : ITensorArithmetic - { - public int One => 1; - public int Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - int sum = (int)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (int)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, int scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (int)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - int sum = (int)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (int)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, int scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (int)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (int)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class LongArithmetic : ITensorArithmetic - { - public long One => 1; - public long Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - long sum = (long)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (long)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, long scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (long)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - long sum = (long)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (long)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, long scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (long)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (long)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class SByteArithmetic : ITensorArithmetic - { - public sbyte One => 1; - public sbyte Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - sbyte sum = (sbyte)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (sbyte)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, sbyte scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (sbyte)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - sbyte sum = (sbyte)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (sbyte)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, sbyte scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (sbyte)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (sbyte)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class ShortArithmetic : ITensorArithmetic - { - public short One => 1; - public short Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - short sum = (short)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (short)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)-tensor[indices]; - } - - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, short scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (short)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - short sum = (short)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (short)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)-tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)-tensorSpan[op1Index]; - - } - } - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, short scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (short)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (short)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class UIntArithmetic : ITensorArithmetic - { - public uint One => 1; - public uint Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - uint sum = (uint)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (uint)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, uint scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (uint)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - uint sum = (uint)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (uint)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, uint scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (uint)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (uint)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class ULongArithmetic : ITensorArithmetic - { - public ulong One => 1; - public ulong Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - ulong sum = (ulong)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (ulong)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, ulong scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ulong)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - ulong sum = (ulong)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (ulong)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, ulong scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ulong)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ulong)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } - internal class UShortArithmetic : ITensorArithmetic - { - public ushort One => 1; - public ushort Zero => 0; - - public void Add(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] + right[indices]); - } - - } - public void Add(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] + scalar); - } - - } - public void And(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] & right[indices]); - } - - } - public void And(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] & scalar); - } - - } - public void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - ushort sum = (ushort)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (ushort)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } - } - public void Decrement(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]--; - } - - } - public void Divide(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] / right[indices]); - } - - } - public void Divide(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] / scalar); - } - - } - public void Equals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] == right[indices]; - } - - } - public void GreaterThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] > right[indices]; - } - - } - public void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] >= right[indices]; - } - - } - public void Increment(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices]++; - } - - } - public void LeftShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] << value); - } - - } - public void LessThan(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] < right[indices]; - } - - } - public void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] <= right[indices]; - } - - } - public void Modulo(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] % right[indices]); - } - - } - public void Modulo(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] % scalar); - } - - } - public void Multiply(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] * right[indices]); - } - - } - public void Multiply(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] * scalar); - } - - } - public void NotEquals(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = left[indices] != right[indices]; - } - - } - public void Or(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] | right[indices]); - } - - } - public void Or(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] | scalar); - } - - } - public void RightShift(Tensor tensor, int value, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] >> value); - } - - } - public void Subtract(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] - right[indices]); - } - - } - public void Subtract(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] - scalar); - } - - } - public void UnaryMinus(Tensor tensor, Tensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(Tensor tensor, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)+tensor[indices]; - } - - } - public void Xor(Tensor left, Tensor right, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(left[indices] ^ right[indices]); - } - - } - public void Xor(Tensor tensor, ushort scalar, Tensor result) - { - - Span indices = new Span(new int[result.Rank]); - for (int i = 0; i < result.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - result[indices] = (ushort)(tensor[indices] ^ scalar); - } - - } - - public void Add(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] + rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] + rightSpan[op2Index]); - - } - } - } - public void Add(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] + scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] + scalar); - - } - } - } - public void And(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] & rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] & rightSpan[op2Index]); - - } - } - } - public void And(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] & scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] & scalar); - - } - } - } - public void Contract(DenseTensor left, DenseTensor right, int[] leftAxes, int[] rightAxes, DenseTensor result) - { - var summingDimensions = new int[leftAxes.Length]; - for (int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - ushort sum = (ushort)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (ushort)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } - } - public void Decrement(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]--; - } - } - public void Divide(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] / rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] / rightSpan[op2Index]); - - } - } - } - public void Divide(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] / scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] / scalar); - - } - } - } - public void Equals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] == rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] == rightSpan[op2Index]; - - } - } - } - public void GreaterThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] > rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] > rightSpan[op2Index]; - - } - } - } - public void GreaterThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] >= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] >= rightSpan[op2Index]; - - } - } - } - public void Increment(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i]++; - } - } - public void LeftShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] << value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] << value); - - } - } - } - public void LessThan(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] < rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] < rightSpan[op2Index]; - - } - } - } - public void LessThanOrEqual(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] <= rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] <= rightSpan[op2Index]; - - } - } - } - public void Modulo(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] % rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] % rightSpan[op2Index]); - - } - } - } - public void Modulo(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] % scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] % scalar); - - } - } - } - public void Multiply(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] * rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] * rightSpan[op2Index]); - - } - } - } - public void Multiply(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] * scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] * scalar); - - } - } - } - public void NotEquals(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = leftSpan[i] != rightSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = leftSpan[op1Index] != rightSpan[op2Index]; - - } - } - } - public void Or(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] | rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] | rightSpan[op2Index]); - - } - } - } - public void Or(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] | scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] | scalar); - - } - } - } - public void RightShift(DenseTensor tensor, int value, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] >> value); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] >> value); - - } - } - } - public void Subtract(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] - rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] - rightSpan[op2Index]); - - } - } - } - public void Subtract(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] - scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] - scalar); - - } - } - } - public void UnaryMinus(DenseTensor tensor, DenseTensor result) - { - throw new NotSupportedException(); - } - public void UnaryPlus(DenseTensor tensor, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)+tensorSpan[i]; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)+tensorSpan[op1Index]; - - } - } - } - public void Xor(DenseTensor left, DenseTensor right, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - if ((result.IsReversedStride == left.IsReversedStride) && (result.IsReversedStride == right.IsReversedStride)) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(leftSpan[i] ^ rightSpan[i]); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref left.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - ref int op2Index = ref right.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - !left.IsReversedStride ? left.strides : - right.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - left.IsReversedStride ? left.strides : - right.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(leftSpan[op1Index] ^ rightSpan[op2Index]); - - } - } - } - public void Xor(DenseTensor tensor, ushort scalar, DenseTensor result) - { - - var resultSpan = result.Buffer.Span; - var tensorSpan = tensor.Buffer.Span; - if (result.IsReversedStride == tensor.IsReversedStride) - { - for (int i = 0; i < resultSpan.Length; i++) - { - resultSpan[i] = (ushort)(tensorSpan[i] ^ scalar); - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref result.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref tensor.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !result.IsReversedStride ? result.strides : - tensor.strides; - var columnMajorStrides = result.IsReversedStride ? result.strides : - tensor.strides; - for (;rowMajorIndex < resultSpan.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - resultSpan[resultIndex] = (ushort)(tensorSpan[op1Index] ^ scalar); - - } - } - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorArithmetic.tt b/src/libraries/System.Numerics.Tensors/tests/TensorArithmetic.tt deleted file mode 100644 index 91efa47c1ab768..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorArithmetic.tt +++ /dev/null @@ -1,237 +0,0 @@ -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ output extension=".cs" #> -<#@ include file="TensorTemplate.ttinclude" #>// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Numerics.Tensors -{ - internal interface ITensorArithmetic - { - T One { get; } - T Zero { get; } -<# foreach (MethodConfiguration method in methodConfiguration) { #> - <#= method.GetResultMethodSignature("Tensor", "T")#>; -<# } #> - } - - internal static class TensorArithmetic - { - public static ITensorArithmetic Instance => TensorArithmetic.GetArithmetic(); - } - - internal static class TensorArithmetic - { - public static ITensorArithmetic GetArithmetic() - { -<# foreach (TypeConfiguration type in typeConfiguration) { #> - <#=GenerateIfStatementHeader(type)#> - { - return (ITensorArithmetic)new <#=type.ClassPrefix#>Arithmetic(); - } -<# } #> - return null; - } - } - -<# foreach (TypeConfiguration type in typeConfiguration) { #> - internal class <#=type.ClassPrefix#>Arithmetic : ITensorArithmetic<<#=type.TypeName#>> - { - public <#=type.TypeName#> One => <#=type.OneLiteral#>; - public <#=type.TypeName#> Zero => <#=type.ZeroLiteral#>; - -<# foreach (MethodConfiguration method in methodConfiguration) { #> - public <#= method.GetResultMethodSignature("Tensor", type.TypeName)#> - { -<# if ((method.IsNumeric && !type.SupportsNumeric) || (method.IsBitwise && !type.SupportsBitwise) || (type.UnsupportedMethods.Contains(method.MethodName))) { #> - throw new NotSupportedException(); -<# } else if (method.Operator != null) { #> - - Span indices = new Span(new int[result.Rank]); - for(int i = 0; i < <#= method.ResultName #>.Length; i++) - { - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, i, indices); - <#=method.GetElementOperation(type.TypeName, "[indices]")#>; - } - -<# } else if (method.MethodName == "Contract") {#> - var leftIndices = new int[left.Rank]; - var rightIndices = new int[right.Rank]; - var resultIndices = new int[result.Rank]; - - var summingDimensions = new int[leftAxes.Length]; - for(int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - for (int resultIndex = 0; resultIndex < result.Length; resultIndex++) - { - <#=type.TypeName#> sum = (<#=type.TypeName#>)0; - - ArrayUtilities.GetIndices(result.strides, result.IsReversedStride, resultIndex, resultIndices); - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - // todo, make this more efficient - ArrayUtilities.GetIndices(left.strides, left.IsReversedStride, leftIndex, leftIndices); - ArrayUtilities.GetIndices(right.strides, right.IsReversedStride, rightIndex, rightIndices); - - sum += (<#=type.TypeName#>)(left[leftIndices] * right[rightIndices]); - } - - result[resultIndices] = sum; - } -<# } #> - } -<# } #> - -<# foreach (MethodConfiguration method in methodConfiguration) { #> - public <#= method.GetResultMethodSignature("DenseTensor", type.TypeName)#> - { -<# if ((method.IsNumeric && !type.SupportsNumeric) || (method.IsBitwise && !type.SupportsBitwise) || (type.UnsupportedMethods.Contains(method.MethodName))) { #> - throw new NotSupportedException(); -<# } else if (method.Operator != null) { #> - -<# if (method.MethodType == MethodType.UnaryInPlace) { #> - var <#=method.ResultName #>Span = <#=method.ResultName #>.Buffer.Span; - var <#=method.Op1Name #>Span = <#=method.Op1Name #>.Buffer.Span; - for(int i = 0; i < <#=method.ResultName #>Span.Length; i++) - { - <#=method.GetElementOperation(type.TypeName, "Span[i]")#>; - } -<# } else {#> - var <#=method.ResultName #>Span = <#=method.ResultName #>.Buffer.Span; - var <#=method.Op1Name #>Span = <#=method.Op1Name #>.Buffer.Span; -<# if ((method.MethodType == MethodType.Binary) || (method.MethodType == MethodType.Comparison)) {#> - var <#=method.Op2Name #>Span = <#=method.Op2Name #>.Buffer.Span; -<# } #> - if <#= method.GetLinearOperationCheck() #> - { - for(int i = 0; i < <#= method.ResultName #>Span.Length; i++) - { - <#=method.GetElementOperation(type.TypeName, "Span[i]")#>; - } - } - else - { - int rowMajorIndex = 0; - int colMajorIndex = 0; - - ref int resultIndex = ref <#= method.ResultName #>.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - ref int op1Index = ref <#= method.Op1Name #>.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - -<# if ((method.MethodType == MethodType.Binary) || (method.MethodType == MethodType.Comparison)) {#> - ref int op2Index = ref <#= method.Op2Name #>.IsReversedStride ? ref colMajorIndex : ref rowMajorIndex; - - var rowMajorStrides = !<#= method.ResultName #>.IsReversedStride ? <#= method.ResultName #>.strides : - !<#= method.Op1Name #>.IsReversedStride ? <#= method.Op1Name #>.strides : - <#= method.Op2Name #>.strides; - var columnMajorStrides = <#= method.ResultName #>.IsReversedStride ? <#= method.ResultName #>.strides : - <#= method.Op1Name #>.IsReversedStride ? <#= method.Op1Name #>.strides : - <#= method.Op2Name #>.strides; -<# } else {#> - var rowMajorStrides = !<#= method.ResultName #>.IsReversedStride ? <#= method.ResultName #>.strides : - <#= method.Op1Name #>.strides; - var columnMajorStrides = <#= method.ResultName #>.IsReversedStride ? <#= method.ResultName #>.strides : - <#= method.Op1Name #>.strides; -<# } #> - for(;rowMajorIndex < <#= method.ResultName #>Span.Length; rowMajorIndex++) - { - colMajorIndex = ArrayUtilities.TransformIndexByStrides(rowMajorIndex, rowMajorStrides, false, columnMajorStrides); - - <#=method.GetElementOperation(type.TypeName, "Span[resultIndex]", "Span[op1Index]", "Span[op2Index]")#>; - - } - } -<# } #> -<# } else if (method.MethodName == "Contract") {#> - var summingDimensions = new int[leftAxes.Length]; - for(int i = 0; i < leftAxes.Length; i++) - { - summingDimensions[i] = left.dimensions[leftAxes[i]]; - } - - var summingStrides = ArrayUtilities.GetStrides(summingDimensions); - int summingLength = (int)ArrayUtilities.GetProduct(summingDimensions); - - var resultStrides = result.strides; - - // translates from result index to left non-summing dimensions' index portion - // since left non-summing dimensions are given precedence in result, the end is zero-padded - int[] leftNonSummingStrides = new int[result.Rank]; - - // translates from summing index to left summing dimensions' index portion - int[] leftSummingStrides = new int[leftAxes.Length]; - ArrayUtilities.SplitStrides(left.strides, leftAxes, leftNonSummingStrides, 0, leftSummingStrides, 0); - - // translates from result index to right non-summing dimensions' index portion - int[] rightNonSummingStrides = new int[result.Rank]; - // right non-summing dimensions appear after left non-summing dimensions. - int rightNonSummingStridesOffset = (left.Rank - leftAxes.Length); - - // translates from summing index to right summing dimensions' index portion - int[] rightSummingStrides = new int[rightAxes.Length]; - ArrayUtilities.SplitStrides(right.strides, rightAxes, rightNonSummingStrides, rightNonSummingStridesOffset, rightSummingStrides, 0); - - var resultSpan = result.Buffer.Span; - var leftSpan = left.Buffer.Span; - var rightSpan = right.Buffer.Span; - - for (int resultIndex = 0; resultIndex < resultSpan.Length; resultIndex++) - { - <#=type.TypeName#> sum = (<#=type.TypeName#>)0; - - int leftIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, leftNonSummingStrides); - int rightIndexNonSumming = ArrayUtilities.TransformIndexByStrides(resultIndex, resultStrides, result.IsReversedStride, rightNonSummingStrides); - - for (int summingIndex = 0; summingIndex < summingLength; summingIndex++) - { - int leftIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, leftSummingStrides); - int rightIndexSumming = ArrayUtilities.TransformIndexByStrides(summingIndex, summingStrides, false, rightSummingStrides); - - int leftIndex = leftIndexNonSumming + leftIndexSumming; - int rightIndex = rightIndexNonSumming + rightIndexSumming; - - sum += (<#=type.TypeName#>)(leftSpan[leftIndex] * rightSpan[rightIndex]); - } - - resultSpan[resultIndex] = sum; - } -<# } #> - } -<# } #> - } -<# } #> -} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorExtensions.cs b/src/libraries/System.Numerics.Tensors/tests/TensorExtensions.cs deleted file mode 100644 index 2aa79f0e120589..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Numerics.Tensors -{ - public static partial class TensorExtensions - { - private static int[] s_zeroArray = new[] { 0 }; - private static int[] s_oneArray = new[] { 1 }; - - internal static Tensor MatrixMultiply(this Tensor left, Tensor right) - { - if (left.Rank != 2) - { - throw new InvalidOperationException($"{nameof(MatrixMultiply)} is only valid for a {nameof(Tensor)} of {nameof(left.Rank)} 2."); - } - - if (right.Rank != 2) - { - throw new ArgumentException($"{nameof(Tensor)} {nameof(right)} must have {nameof(left.Rank)} 2.", nameof(right)); - } - - if (left.dimensions[1] != right.dimensions[0]) - { - throw new ArgumentException($"{nameof(Tensor)} {nameof(right)} must have first dimension of {left.dimensions[1]}.", nameof(right)); - } - - return TensorOperations.Contract(left, right, s_oneArray, s_zeroArray); - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorOperations.cs b/src/libraries/System.Numerics.Tensors/tests/TensorOperations.cs deleted file mode 100644 index 009ad006b88c53..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorOperations.cs +++ /dev/null @@ -1,738 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Numerics.Tensors -{ - public static partial class TensorOperations - { - internal static void ValidateBinaryArgs(Tensor left, Tensor right) - { - if (left.Rank != right.Rank || left.Length != right.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(left)); - } - - for (int i = 0; i < left.Rank; i++) - { - if (left.dimensions[i] != right.dimensions[i]) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - } - } - - internal static void ValidateBinaryArgs(Tensor left, Tensor right, Tensor result) - { - if (left.Rank != right.Rank || left.Length != right.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.Rank != result.Rank || left.Length != result.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(result)); - } - - if (left.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(left)); - } - - for (int i = 0; i < result.Rank; i++) - { - if (left.dimensions[i] != right.dimensions[i]) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.dimensions[i] != result.dimensions[i]) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - } - } - - internal static void ValidateBinaryArgs(Tensor left, Tensor right, Tensor result) - { - if (left.Rank != right.Rank || left.Length != right.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.Rank != result.Rank || left.Length != result.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(result)); - } - - if (left.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(left)); - } - - for (int i = 0; i < result.Rank; i++) - { - if (left.dimensions[i] != right.dimensions[i]) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.dimensions[i] != result.dimensions[i]) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - } - } - - internal static void ValidateArgs(Tensor tensor) - { - if (tensor.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(tensor)); - } - } - - internal static void ValidateArgs(Tensor tensor, Tensor result) - { - if (tensor.Rank != result.Rank || tensor.Length != result.Length) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - - if (tensor.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(tensor)); - } - - for (int i = 0; i < result.Rank; i++) - { - if (tensor.dimensions[i] != result.dimensions[i]) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - } - } - - internal static int[] ValidateContractArgs(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes) - { - if (leftAxes == null) - { - throw new ArgumentNullException(nameof(left)); - } - - if (rightAxes == null) - { - throw new ArgumentNullException(nameof(left)); - } - - if (leftAxes.Length != rightAxes.Length) - { - throw new ArgumentException($"{nameof(leftAxes)} and {nameof(rightAxes)} must have the same length, but were {leftAxes.Length} and {rightAxes.Length}, respectively."); - } - - for (int i = 0; i < leftAxes.Length; i++) - { - var leftAxis = leftAxes[i]; - - if (leftAxis >= left.Rank) - { - throw new ArgumentOutOfRangeException($"{nameof(leftAxes)}[{i}] was set to axis index {leftAxis} which exceeds the Rank of {left}."); - } - - var leftDimension = left.dimensions[leftAxis]; - - var rightAxis = rightAxes[i]; - - if (rightAxis >= right.Rank) - { - throw new ArgumentOutOfRangeException($"{nameof(rightAxes)}[{i}] was set to axis index {rightAxis} which exceeds the Rank of {right}."); - } - - var rightDimension = right.dimensions[rightAxis]; - - if (leftDimension != rightDimension) - { - throw new ArgumentOutOfRangeException($"Tensors may only be contracted on axes of the same length, but {nameof(leftAxes)} index {i} was length {leftDimension} and {nameof(rightAxes)} index {i} was length {rightDimension}."); - } - } - - var leftNonSummingDimensions = left.Rank - leftAxes.Length; - var rightNonSummingDimensions = right.Rank - rightAxes.Length; - var resultDimensions = new int[leftNonSummingDimensions + rightNonSummingDimensions]; - int dimensionsIndex = 0; - - Action, int[]> fillDimensions = (tensor, axes) => - { - for (int i = 0; i < tensor.Rank; i++) - { - var skip = false; - foreach (var contractionIndex in axes) - { - if (contractionIndex == i) - { - skip = true; - break; - } - } - - if (!skip) - { - resultDimensions[dimensionsIndex++] = tensor.dimensions[i]; - } - } - }; - - fillDimensions(left, leftAxes); - fillDimensions(right, rightAxes); - - return resultDimensions; - } - - internal static int[] ValidateContractArgs(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var expectedDimensions = ValidateContractArgs(left, right, leftAxes, rightAxes); - - if (result.Rank != expectedDimensions.Length) - { - throw new ArgumentException($"{nameof(result)} should have {expectedDimensions.Length} dimensions but had {result.Rank}."); - } - - for (int i = 0; i < expectedDimensions.Length; i++) - { - if (result.dimensions[i] != expectedDimensions[i]) - { - throw new ArgumentException($"{nameof(result)} dimension {i} should be {expectedDimensions[i]} but was {result.dimensions[i]}."); - } - } - - return expectedDimensions; - } - - internal static void Add(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Add(left, right, result); - } - - internal static Tensor Add(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Add(left, right, result); - - return result; - } - - internal static void Add(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Add(tensor, scalar, result); - } - - internal static Tensor Add(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Add(tensor, scalar, result); - - return result; - } - - internal static void And(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.And(left, right, result); - } - - internal static Tensor And(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.And(left, right, result); - - return result; - } - - internal static void And(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.And(tensor, scalar, result); - } - - internal static Tensor And(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.And(tensor, scalar, result); - - return result; - } - - internal static void Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - ValidateContractArgs(left, right, leftAxes, rightAxes, result); - - TensorArithmetic.Instance.Contract(left, right, leftAxes, rightAxes, result); - } - - internal static Tensor Contract(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes) - { - var resultDimensions = ValidateContractArgs(left, right, leftAxes, rightAxes); - - var result = left.CloneEmpty(resultDimensions); - - TensorArithmetic.Instance.Contract(left, right, leftAxes, rightAxes, result); - - return result; - } - - internal static void Decrement(Tensor tensor, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Decrement(tensor, result); - } - - internal static Tensor Decrement(Tensor tensor) - { - ValidateArgs(tensor); - - var result = tensor.Clone(); - - TensorArithmetic.Instance.Decrement(tensor, result); - - return result; - } - - internal static void Divide(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Divide(left, right, result); - } - - internal static Tensor Divide(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Divide(left, right, result); - - return result; - } - - internal static void Divide(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Divide(tensor, scalar, result); - } - - internal static Tensor Divide(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Divide(tensor, scalar, result); - - return result; - } - - internal static void Equals(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Equals(left, right, result); - } - - internal static Tensor Equals(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Equals(left, right, result); - - return result; - } - - internal static void GreaterThan(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.GreaterThan(left, right, result); - } - - internal static Tensor GreaterThan(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.GreaterThan(left, right, result); - - return result; - } - - internal static void GreaterThanOrEqual(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.GreaterThanOrEqual(left, right, result); - } - - internal static Tensor GreaterThanOrEqual(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.GreaterThanOrEqual(left, right, result); - - return result; - } - - internal static void Increment(Tensor tensor, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Increment(tensor, result); - } - - internal static Tensor Increment(Tensor tensor) - { - ValidateArgs(tensor); - - var result = tensor.Clone(); - - TensorArithmetic.Instance.Increment(tensor, result); - - return result; - } - - internal static void LeftShift(Tensor tensor, int value, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.LeftShift(tensor, value, result); - } - - internal static Tensor LeftShift(Tensor tensor, int value) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.LeftShift(tensor, value, result); - - return result; - } - - internal static void LessThan(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.LessThan(left, right, result); - } - - internal static Tensor LessThan(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.LessThan(left, right, result); - - return result; - } - - internal static void LessThanOrEqual(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.LessThanOrEqual(left, right, result); - } - - internal static Tensor LessThanOrEqual(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.LessThanOrEqual(left, right, result); - - return result; - } - - internal static void Modulo(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Modulo(left, right, result); - } - - internal static Tensor Modulo(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Modulo(left, right, result); - - return result; - } - - internal static void Modulo(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Modulo(tensor, scalar, result); - } - - internal static Tensor Modulo(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Modulo(tensor, scalar, result); - - return result; - } - - internal static void Multiply(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Multiply(left, right, result); - } - - internal static Tensor Multiply(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Multiply(left, right, result); - - return result; - } - - internal static void Multiply(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Multiply(tensor, scalar, result); - } - - internal static Tensor Multiply(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Multiply(tensor, scalar, result); - - return result; - } - - internal static void NotEquals(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.NotEquals(left, right, result); - } - - internal static Tensor NotEquals(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.NotEquals(left, right, result); - - return result; - } - - internal static void Or(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Or(left, right, result); - } - - internal static Tensor Or(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Or(left, right, result); - - return result; - } - - internal static void Or(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Or(tensor, scalar, result); - } - - internal static Tensor Or(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Or(tensor, scalar, result); - - return result; - } - - internal static void RightShift(Tensor tensor, int value, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.RightShift(tensor, value, result); - } - - internal static Tensor RightShift(Tensor tensor, int value) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.RightShift(tensor, value, result); - - return result; - } - - internal static void Subtract(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Subtract(left, right, result); - } - - internal static Tensor Subtract(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Subtract(left, right, result); - - return result; - } - - internal static void Subtract(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Subtract(tensor, scalar, result); - } - - internal static Tensor Subtract(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Subtract(tensor, scalar, result); - - return result; - } - - internal static void UnaryMinus(Tensor tensor, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.UnaryMinus(tensor, result); - } - - internal static Tensor UnaryMinus(Tensor tensor) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.UnaryMinus(tensor, result); - - return result; - } - - internal static void UnaryPlus(Tensor tensor, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.UnaryPlus(tensor, result); - } - - internal static Tensor UnaryPlus(Tensor tensor) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.UnaryPlus(tensor, result); - - return result; - } - - internal static void Xor(Tensor left, Tensor right, Tensor result) - { - ValidateBinaryArgs(left, right, result); - - TensorArithmetic.Instance.Xor(left, right, result); - } - - internal static Tensor Xor(Tensor left, Tensor right) - { - ValidateBinaryArgs(left, right); - - var result = left.CloneEmpty(); - - TensorArithmetic.Instance.Xor(left, right, result); - - return result; - } - - internal static void Xor(Tensor tensor, T scalar, Tensor result) - { - ValidateArgs(tensor, result); - - TensorArithmetic.Instance.Xor(tensor, scalar, result); - } - - internal static Tensor Xor(Tensor tensor, T scalar) - { - ValidateArgs(tensor); - - var result = tensor.CloneEmpty(); - - TensorArithmetic.Instance.Xor(tensor, scalar, result); - - return result; - } - - } -} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorOperations.tt b/src/libraries/System.Numerics.Tensors/tests/TensorOperations.tt deleted file mode 100644 index 6b96c0bb554a5a..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorOperations.tt +++ /dev/null @@ -1,239 +0,0 @@ -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ output extension=".cs" #> -<#@ include file="TensorTemplate.ttinclude" #>// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Numerics.Tensors -{ - public static partial class TensorOperations - { - internal static void ValidateBinaryArgs(Tensor left, Tensor right) - { - if (left.Rank != right.Rank || left.Length != right.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(left)); - } - - for (int i = 0; i < left.Rank; i++) - { - if (left.dimensions[i] != right.dimensions[i]) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - } - } - - internal static void ValidateBinaryArgs(Tensor left, Tensor right, Tensor result) - { - if (left.Rank != right.Rank || left.Length != right.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.Rank != result.Rank || left.Length != result.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(result)); - } - - if (left.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(left)); - } - - for (int i = 0; i < result.Rank; i++) - { - if (left.dimensions[i] != right.dimensions[i]) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.dimensions[i] != result.dimensions[i]) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - } - } - - internal static void ValidateBinaryArgs(Tensor left, Tensor right, Tensor result) - { - if (left.Rank != right.Rank || left.Length != right.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.Rank != result.Rank || left.Length != result.Length) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(result)); - } - - if (left.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(left)); - } - - for (int i = 0; i < result.Rank; i++) - { - if (left.dimensions[i] != right.dimensions[i]) - { - throw new ArgumentException("Operands must have matching dimensions", nameof(right)); - } - - if (left.dimensions[i] != result.dimensions[i]) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - } - } - - internal static void ValidateArgs(Tensor tensor) - { - if (tensor.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(tensor)); - } - } - - internal static void ValidateArgs(Tensor tensor, Tensor result) - { - if (tensor.Rank != result.Rank || tensor.Length != result.Length) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - - if (tensor.Rank == 0) - { - throw new ArgumentException($"Cannot operate on Tensor with {nameof(Tensor.Rank)} of 0.", nameof(tensor)); - } - - for (int i = 0; i < result.Rank; i++) - { - if (tensor.dimensions[i] != result.dimensions[i]) - { - throw new ArgumentException("Operands and result must have matching dimensions", nameof(result)); - } - } - } - - internal static int[] ValidateContractArgs(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes) - { - if (leftAxes == null) - { - throw new ArgumentNullException(nameof(left)); - } - - if (rightAxes == null) - { - throw new ArgumentNullException(nameof(left)); - } - - if (leftAxes.Length != rightAxes.Length) - { - throw new ArgumentException($"{nameof(leftAxes)} and {nameof(rightAxes)} must have the same length, but were {leftAxes.Length} and {rightAxes.Length}, respectively."); - } - - for (int i = 0; i < leftAxes.Length; i++) - { - var leftAxis = leftAxes[i]; - - if (leftAxis >= left.Rank) - { - throw new ArgumentOutOfRangeException($"{nameof(leftAxes)}[{i}] was set to axis index {leftAxis} which exceeds the Rank of {left}."); - } - - var leftDimension = left.dimensions[leftAxis]; - - var rightAxis = rightAxes[i]; - - if (rightAxis >= right.Rank) - { - throw new ArgumentOutOfRangeException($"{nameof(rightAxes)}[{i}] was set to axis index {rightAxis} which exceeds the Rank of {right}."); - } - - var rightDimension = right.dimensions[rightAxis]; - - if (leftDimension != rightDimension) - { - throw new ArgumentOutOfRangeException($"Tensors may only be contracted on axes of the same length, but {nameof(leftAxes)} index {i} was length {leftDimension} and {nameof(rightAxes)} index {i} was length {rightDimension}."); - } - } - - var leftNonSummingDimensions = left.Rank - leftAxes.Length; - var rightNonSummingDimensions = right.Rank - rightAxes.Length; - var resultDimensions = new int[leftNonSummingDimensions + rightNonSummingDimensions]; - int dimensionsIndex = 0; - - Action, int[]> fillDimensions = (tensor, axes) => - { - for (int i = 0; i < tensor.Rank; i++) - { - var skip = false; - foreach (var contractionIndex in axes) - { - if (contractionIndex == i) - { - skip = true; - break; - } - } - - if (!skip) - { - resultDimensions[dimensionsIndex++] = tensor.dimensions[i]; - } - } - }; - - fillDimensions(left, leftAxes); - fillDimensions(right, rightAxes); - - return resultDimensions; - } - - internal static int[] ValidateContractArgs(Tensor left, Tensor right, int[] leftAxes, int[] rightAxes, Tensor result) - { - var expectedDimensions = ValidateContractArgs(left, right, leftAxes, rightAxes); - - if (result.Rank != expectedDimensions.Length) - { - throw new ArgumentException($"{nameof(result)} should have {expectedDimensions.Length} dimensions but had {result.Rank}."); - } - - for (int i = 0; i < expectedDimensions.Length; i++) - { - if (result.dimensions[i] != expectedDimensions[i]) - { - throw new ArgumentException($"{nameof(result)} dimension {i} should be {expectedDimensions[i]} but was {result.dimensions[i]}."); - } - } - - return expectedDimensions; - } - -<# foreach (MethodConfiguration method in methodConfiguration) { #> - internal static <#= method.GetGenericResultMethodSignature("Tensor", "T")#> - { - <#= method.GetValidationMethod(true) #> - - TensorArithmetic.Instance.<#=method.MethodName#>(<#=method.GetCallArguments()#>, <#= method.ResultName #>); - } - - internal static <#= method.GetGenericMethodSignature("Tensor", "T")#> - { - <#= method.GetValidationMethod(false) #> - - var <#= method.ResultName #> = <#=method.InitializeResult("T")#>; - - TensorArithmetic.Instance.<#=method.MethodName#>(<#=method.GetCallArguments()#>, <#= method.ResultName #>); - - return <#= method.ResultName #>; - } - -<# } #> - } -} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs new file mode 100644 index 00000000000000..181d152e6ae979 --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs @@ -0,0 +1,1484 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using Xunit; + +#pragma warning disable xUnit1025 // reporting duplicate test cases due to not distinguishing 0.0 from -0.0 + +namespace System.Numerics.Tensors.Tests +{ + public static partial class TensorPrimitivesTests + { + private const double Tolerance = 0.0001; + + public static IEnumerable TensorLengths => + from length in Enumerable.Range(1, 128) + select new object[] { length }; + + private static readonly Random s_random = new Random(20230828); + + private static BoundedMemory CreateTensor(int size) => BoundedMemory.Allocate(size); + + private static BoundedMemory CreateAndFillTensor(int size) + { + BoundedMemory tensor = CreateTensor(size); + FillTensor(tensor.Span); + return tensor; + } + + private static void FillTensor(Span tensor) + { + for (int i = 0; i < tensor.Length; i++) + { + tensor[i] = NextSingle(); + } + } + + private static float NextSingle() + { + // For testing purposes, get a mix of negative and positive values. + return (float)((s_random.NextDouble() * 2) - 1); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Add(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] + y[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.Add(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Add(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTensorAndScalar(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Add(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] + y, destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTensorAndScalar_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Add(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SubtractTwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Subtract(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] - y[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SubtractTwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.Subtract(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SubtractTwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Subtract(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SubtractTensorAndScalar(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Subtract(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] - y, destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SubtractTensorAndScalar_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Subtract(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Multiply(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] * y[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.Multiply(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Multiply(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTensorAndScalar(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Multiply(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] * y, destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTensorAndScalar_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Multiply(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void DivideTwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Divide(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] / y[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void DivideTwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.Divide(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void DivideTwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Divide(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void DivideTensorAndScalar(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Divide(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(x[i] / y, destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void DivideTensorAndScalar_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Divide(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void NegateTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Negate(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(-x[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void NegateTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Negate(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithThirdTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.AddMultiply(x, y, multiplier, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal((x[i] + y[i]) * multiplier[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithThirdTensor_ThrowsForMismatchedLengths_x_y(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithThirdTensor_ThrowsForMismatchedLengths_x_multiplier(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithThirdTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithScalar(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + float multiplier = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.AddMultiply(x, y, multiplier, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal((x[i] + y[i]) * multiplier, destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithScalar_ThrowsForMismatchedLengths_x_y(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + float multiplier = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTwoTensorsAndMultiplyWithScalar_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + float multiplier = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTensorAndScalarAndMultiplyWithTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.AddMultiply(x, y, multiplier, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal((x[i] + y) * multiplier[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTensorAndScalarAndMultiplyWithTensor_ThrowsForMismatchedLengths_x_z(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void AddTensorAndScalarAndMultiplyWithTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory multiplier = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.AddMultiply(x, y, multiplier, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensorsAndAddWithThirdTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory addend = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.MultiplyAdd(x, y, addend, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal((x[i] * y[i]) + addend[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensorsAndAddWithThirdTensor_ThrowsForMismatchedLengths_x_y(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory addend = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.MultiplyAdd(x, y, addend, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensorsAndAddWithThirdTensor_ThrowsForMismatchedLengths_x_multiplier(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory addend = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.MultiplyAdd(x, y, addend, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensorsAndAddWithThirdTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory addend = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.MultiplyAdd(x, y, addend, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensorsAndAddWithScalar(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + float addend = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.MultiplyAdd(x, y, addend, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal((x[i] * y[i]) + addend, destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTwoTensorsAndAddWithScalar_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + float addend = NextSingle(); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.MultiplyAdd(x, y, addend, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTensorAndScalarAndAddWithTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory addend = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.MultiplyAdd(x, y, addend, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal((x[i] * y) + addend[i], destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MultiplyTensorAndScalarAndAddWithTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + float y = NextSingle(); + using BoundedMemory addend = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.MultiplyAdd(x, y, addend, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void ExpTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Exp(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Exp(x[i]), destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void ExpTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Exp(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void LogTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Log(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Log(x[i]), destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void LogTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Log(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void CoshTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Cosh(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Cosh(x[i]), destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void CoshTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Cosh(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SinhTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Sinh(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Sinh(x[i]), destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SinhTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Sinh(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void TanhTensor(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Tanh(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Tanh(x[i]), destination[i]); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void TanhTensor_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Tanh(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void CosineSimilarity_ThrowsForMismatchedLengths_x_y(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + + Assert.Throws(() => TensorPrimitives.CosineSimilarity(x, y)); + } + + [Fact] + public static void CosineSimilarity_ThrowsForEmpty_x_y() + { + Assert.Throws(() => TensorPrimitives.CosineSimilarity(ReadOnlySpan.Empty, ReadOnlySpan.Empty)); + Assert.Throws(() => TensorPrimitives.CosineSimilarity(ReadOnlySpan.Empty, CreateTensor(1))); + Assert.Throws(() => TensorPrimitives.CosineSimilarity(CreateTensor(1), ReadOnlySpan.Empty)); + } + + [Theory] + [InlineData(new float[] { 3, 2, 0, 5 }, new float[] { 1, 0, 0, 0 }, 0.48666f)] + [InlineData(new float[] { 1, 1, 1, 1, 1, 0 }, new float[] { 1, 1, 1, 1, 0, 1 }, 0.80f)] + public static void CosineSimilarity_KnownValues(float[] x, float[] y, float expectedResult) + { + Assert.Equal(expectedResult, TensorPrimitives.CosineSimilarity(x, y), Tolerance); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void CosineSimilarity(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + + float dot = 0f, squareX = 0f, squareY = 0f; + for (int i = 0; i < x.Length; i++) + { + dot += x[i] * y[i]; + squareX += x[i] * x[i]; + squareY += y[i] * y[i]; + } + + Assert.Equal(dot / (Math.Sqrt(squareX) * Math.Sqrt(squareY)), TensorPrimitives.CosineSimilarity(x, y), Tolerance); + } + + [Fact] + public static void Distance_ThrowsForEmpty_x_y() + { + Assert.Throws(() => TensorPrimitives.Distance(ReadOnlySpan.Empty, ReadOnlySpan.Empty)); + Assert.Throws(() => TensorPrimitives.Distance(ReadOnlySpan.Empty, CreateTensor(1))); + Assert.Throws(() => TensorPrimitives.Distance(CreateTensor(1), ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Distance_ThrowsForMismatchedLengths_x_y(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + + Assert.Throws(() => TensorPrimitives.Distance(x, y)); + } + + [Theory] + [InlineData(new float[] { 3, 2 }, new float[] { 4, 1 }, 1.4142f)] + [InlineData(new float[] { 0, 4 }, new float[] { 6, 2 }, 6.3245f)] + [InlineData(new float[] { 1, 2, 3 }, new float[] { 4, 5, 6 }, 5.1961f)] + [InlineData(new float[] { 5, 1, 6, 10 }, new float[] { 7, 2, 8, 4 }, 6.7082f)] + public static void Distance_KnownValues(float[] x, float[] y, float expectedResult) + { + Assert.Equal(expectedResult, TensorPrimitives.Distance(x, y), Tolerance); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Distance(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + + float distance = 0f; + for (int i = 0; i < x.Length; i++) + { + distance += (x[i] - y[i]) * (x[i] - y[i]); + } + + Assert.Equal(Math.Sqrt(distance), TensorPrimitives.Distance(x, y), Tolerance); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Dot_ThrowsForMismatchedLengths_x_y(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + + Assert.Throws(() => TensorPrimitives.Dot(x, y)); + } + + [Theory] + [InlineData(new float[] { 1, 3, -5 }, new float[] { 4, -2, -1 }, 3)] + [InlineData(new float[] { 1, 2, 3 }, new float[] { 4, 5, 6 }, 32)] + [InlineData(new float[] { 1, 2, 3, 10, 8 }, new float[] { 4, 5, 6, -2, 7 }, 68)] + [InlineData(new float[] { }, new float[] { }, 0)] + public static void Dot_KnownValues(float[] x, float[] y, float expectedResult) + { + Assert.Equal(expectedResult, TensorPrimitives.Dot(x, y), Tolerance); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Dot(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + + float dot = 0f; + for (int i = 0; i < x.Length; i++) + { + dot += x[i] * y[i]; + } + + Assert.Equal(dot, TensorPrimitives.Dot(x, y), Tolerance); + } + + [Theory] + [InlineData(new float[] { 1, 2, 3 }, 3.7416575f)] + [InlineData(new float[] { 3, 4 }, 5)] + [InlineData(new float[] { 3 }, 3)] + [InlineData(new float[] { 3, 4, 1, 2 }, 5.477226)] + [InlineData(new float[] { }, 0f)] + public static void L2Normalize_KnownValues(float[] x, float expectedResult) + { + Assert.Equal(expectedResult, TensorPrimitives.L2Normalize(x), Tolerance); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void L2Normalize(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + float sumOfSquares = 0f; + for (int i = 0; i < x.Length; i++) + { + sumOfSquares += x[i] * x[i]; + } + + Assert.Equal(Math.Sqrt(sumOfSquares), TensorPrimitives.L2Normalize(x), Tolerance); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SoftMax_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.SoftMax(x, destination)); + } + + [Theory] + [InlineData(new float[] { 3, 1, .2f }, new float[] { 0.8360188f, 0.11314284f, 0.05083836f })] + [InlineData(new float[] { 3, 4, 1 }, new float[] { 0.2594f, 0.705384f, 0.0351f })] + [InlineData(new float[] { 5, 3 }, new float[] { 0.8807f, 0.1192f })] + [InlineData(new float[] { 4, 2, 1, 9 }, new float[] { 0.0066f, 9.04658e-4f, 3.32805e-4f, 0.9920f})] + public static void SoftMax(float[] x, float[] expectedResult) + { + using BoundedMemory dest = CreateTensor(x.Length); + TensorPrimitives.SoftMax(x, dest); + + for (int i = 0; i < x.Length; i++) + { + Assert.Equal(expectedResult[i], dest[i], Tolerance); + } + } + + [Fact] + public static void SoftMax_DestinationLongerThanSource() + { + float[] x = [3, 1, .2f]; + float[] expectedResult = [0.8360188f, 0.11314284f, 0.05083836f]; + using BoundedMemory dest = CreateTensor(x.Length + 1); + TensorPrimitives.SoftMax(x, dest); + + for (int i = 0; i < x.Length; i++) + { + Assert.Equal(expectedResult[i], dest[i], Tolerance); + } + } + + [Fact] + public static void SoftMax_ThrowsForEmptyInput() + { + AssertExtensions.Throws(() => TensorPrimitives.SoftMax(ReadOnlySpan.Empty, CreateTensor(1))); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Sigmoid_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Sigmoid(x, destination)); + } + + [Theory] + [InlineData(new float[] { -5, -4.5f, -4 }, new float[] { 0.0066f, 0.0109f, 0.0179f })] + [InlineData(new float[] { 4.5f, 5 }, new float[] { 0.9890f, 0.9933f })] + [InlineData(new float[] { 0, -3, 3, .5f }, new float[] { 0.5f, 0.0474f, 0.9525f, 0.6224f })] + public static void Sigmoid(float[] x, float[] expectedResult) + { + using BoundedMemory dest = CreateTensor(x.Length); + TensorPrimitives.Sigmoid(x, dest); + + for (int i = 0; i < x.Length; i++) + { + Assert.Equal(expectedResult[i], dest[i], Tolerance); + } + } + + [Fact] + public static void Sigmoid_DestinationLongerThanSource() + { + float[] x = [-5, -4.5f, -4]; + float[] expectedResult = [0.0066f, 0.0109f, 0.0179f]; + using BoundedMemory dest = CreateTensor(x.Length + 1); + + TensorPrimitives.Sigmoid(x, dest); + + float originalLast = dest[dest.Length - 1]; + for (int i = 0; i < x.Length; i++) + { + Assert.Equal(expectedResult[i], dest[i], Tolerance); + } + Assert.Equal(originalLast, dest[dest.Length - 1]); + } + + [Fact] + public static void Sigmoid_ThrowsForEmptyInput() + { + AssertExtensions.Throws(() => TensorPrimitives.Sigmoid(ReadOnlySpan.Empty, CreateTensor(1))); + } + + [Fact] + public static void IndexOfMax_ReturnsNegative1OnEmpty() + { + Assert.Equal(-1, TensorPrimitives.IndexOfMax(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMax(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = Enumerable.Max(MemoryMarshal.ToEnumerable(x.Memory)) + 1; + Assert.Equal(expected, TensorPrimitives.IndexOfMax(x)); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMax_FirstNaNReturned(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = float.NaN; + x[tensorLength - 1] = float.NaN; + Assert.Equal(expected, TensorPrimitives.IndexOfMax(x)); + } + } + + [Fact] + public static void IndexOfMax_Negative0LesserThanPositive0() + { + Assert.Equal(1, TensorPrimitives.IndexOfMax([-0f, +0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMax([-0f, -0f, -0f, -0f])); + Assert.Equal(4, TensorPrimitives.IndexOfMax([-0f, -0f, -0f, -0f, +0f, +0f, +0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMax([+0f, -0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMax([-1, -0f])); + Assert.Equal(2, TensorPrimitives.IndexOfMax([-1, -0f, 1])); + } + + [Fact] + public static void IndexOfMin_ReturnsNegative1OnEmpty() + { + Assert.Equal(-1, TensorPrimitives.IndexOfMin(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMin(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = Enumerable.Min(MemoryMarshal.ToEnumerable(x.Memory)) - 1; + Assert.Equal(expected, TensorPrimitives.IndexOfMin(x)); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMin_FirstNaNReturned(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = float.NaN; + x[tensorLength - 1] = float.NaN; + Assert.Equal(expected, TensorPrimitives.IndexOfMin(x)); + } + } + + [Fact] + public static void IndexOfMin_Negative0LesserThanPositive0() + { + Assert.Equal(0, TensorPrimitives.IndexOfMin([-0f, +0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMin([+0f, -0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMin([+0f, -0f, -0f, -0f, -0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMin([-1, -0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMin([-1, -0f, 1])); + } + + [Fact] + public static void IndexOfMaxMagnitude_ReturnsNegative1OnEmpty() + { + Assert.Equal(-1, TensorPrimitives.IndexOfMaxMagnitude(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMaxMagnitude(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = Enumerable.Max(MemoryMarshal.ToEnumerable(x.Memory), Math.Abs) + 1; + Assert.Equal(expected, TensorPrimitives.IndexOfMaxMagnitude(x)); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMaxMagnitude_FirstNaNReturned(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = float.NaN; + x[tensorLength - 1] = float.NaN; + Assert.Equal(expected, TensorPrimitives.IndexOfMaxMagnitude(x)); + } + } + + [Fact] + public static void IndexOfMaxMagnitude_Negative0LesserThanPositive0() + { + Assert.Equal(0, TensorPrimitives.IndexOfMaxMagnitude([-0f, -0f, -0f, -0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMaxMagnitude([-0f, +0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMaxMagnitude([-0f, +0f, +0f, +0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMaxMagnitude([+0f, -0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMaxMagnitude([-1, -0f])); + Assert.Equal(2, TensorPrimitives.IndexOfMaxMagnitude([-1, -0f, 1])); + } + + [Fact] + public static void IndexOfMinMagnitude_ReturnsNegative1OnEmpty() + { + Assert.Equal(-1, TensorPrimitives.IndexOfMinMagnitude(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMinMagnitude(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateTensor(tensorLength); + for (int i = 0; i < x.Length; i++) + { + x[i] = i % 2 == 0 ? 42 : -42; + } + + x[expected] = -41; + + Assert.Equal(expected, TensorPrimitives.IndexOfMinMagnitude(x)); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void IndexOfMinMagnitude_FirstNaNReturned(int tensorLength) + { + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + x[expected] = float.NaN; + x[tensorLength - 1] = float.NaN; + Assert.Equal(expected, TensorPrimitives.IndexOfMinMagnitude(x)); + } + } + + [Fact] + public static void IndexOfMinMagnitude_Negative0LesserThanPositive0() + { + Assert.Equal(0, TensorPrimitives.IndexOfMinMagnitude([-0f, -0f, -0f, -0f])); + Assert.Equal(0, TensorPrimitives.IndexOfMinMagnitude([-0f, +0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMinMagnitude([+0f, -0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMinMagnitude([+0f, -0f, -0f, -0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMinMagnitude([-1, -0f])); + Assert.Equal(1, TensorPrimitives.IndexOfMinMagnitude([-1, -0f, 1])); + } + + [Fact] + public static void Max_ThrowsForEmpty() + { + Assert.Throws(() => TensorPrimitives.Max(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Max(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Max(MemoryMarshal.ToEnumerable(x.Memory)), TensorPrimitives.Max(x)); + + float max = float.NegativeInfinity; + foreach (float f in x.Span) + { + max = Math.Max(max, f); + } + Assert.Equal(max, TensorPrimitives.Max(x)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Max_NanReturned(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + x[expected] = float.NaN; + Assert.Equal(float.NaN, TensorPrimitives.Max(x)); + } + } + + [Fact] + public static void Max_Negative0LesserThanPositive0() + { + Assert.Equal(+0f, TensorPrimitives.Max([-0f, +0f])); + Assert.Equal(+0f, TensorPrimitives.Max([+0f, -0f])); + Assert.Equal(-0f, TensorPrimitives.Max([-1, -0f])); + Assert.Equal(1, TensorPrimitives.Max([-1, -0f, 1])); + } + + [Fact] + public static void MaxMagnitude_ThrowsForEmpty() + { + Assert.Throws(() => TensorPrimitives.MaxMagnitude(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MaxMagnitude(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Max(MemoryMarshal.ToEnumerable(x.Memory), MathF.Abs), TensorPrimitives.MaxMagnitude(x)); + + float max = 0; + foreach (float f in x.Span) + { + max = Math.Max(max, MathF.Abs(f)); + } + Assert.Equal(max, TensorPrimitives.MaxMagnitude(x)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MaxMagnitude_NanReturned(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + x[expected] = float.NaN; + Assert.Equal(float.NaN, TensorPrimitives.MaxMagnitude(x)); + } + } + + [Fact] + public static void MaxMagnitude_Negative0LesserThanPositive0() + { + Assert.Equal(+0f, TensorPrimitives.MaxMagnitude([-0f, +0f])); + Assert.Equal(+0f, TensorPrimitives.MaxMagnitude([+0f, -0f])); + Assert.Equal(1, TensorPrimitives.MaxMagnitude([-1, -0f])); + Assert.Equal(1, TensorPrimitives.MaxMagnitude([-1, -0f, 1])); + Assert.Equal(0f, TensorPrimitives.MaxMagnitude([-0f, -0f, -0f, -0f, -0f, 0f])); + Assert.Equal(1, TensorPrimitives.MaxMagnitude([-0f, -0f, -0f, -0f, -1, -0f, 0f, 1])); + } + + [Fact] + public static void Min_ThrowsForEmpty() + { + Assert.Throws(() => TensorPrimitives.Min(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Min(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Min(MemoryMarshal.ToEnumerable(x.Memory)), TensorPrimitives.Min(x)); + + float min = float.PositiveInfinity; + foreach (float f in x.Span) + { + min = Math.Min(min, f); + } + Assert.Equal(min, TensorPrimitives.Min(x)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Min_NanReturned(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + x[expected] = float.NaN; + Assert.Equal(float.NaN, TensorPrimitives.Min(x)); + } + } + + [Fact] + public static void Min_Negative0LesserThanPositive0() + { + Assert.Equal(-0f, TensorPrimitives.Min([-0f, +0f])); + Assert.Equal(-0f, TensorPrimitives.Min([+0f, -0f])); + Assert.Equal(-1, TensorPrimitives.Min([-1, -0f])); + Assert.Equal(-1, TensorPrimitives.Min([-1, -0f, 1])); + } + + [Fact] + public static void MinMagnitude_ThrowsForEmpty() + { + Assert.Throws(() => TensorPrimitives.MinMagnitude(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MinMagnitude(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Min(MemoryMarshal.ToEnumerable(x.Memory), MathF.Abs), TensorPrimitives.MinMagnitude(x)); + + float min = float.PositiveInfinity; + foreach (float f in x.Span) + { + min = Math.Min(min, MathF.Abs(f)); + } + Assert.Equal(min, TensorPrimitives.MinMagnitude(x)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MinMagnitude_NanReturned(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + foreach (int expected in new[] { 0, tensorLength / 2, tensorLength - 1 }) + { + x[expected] = float.NaN; + Assert.Equal(float.NaN, TensorPrimitives.MinMagnitude(x)); + } + } + + [Fact] + public static void MinMagnitude_Negative0LesserThanPositive0() + { + Assert.Equal(0, TensorPrimitives.MinMagnitude([-0f, +0f])); + Assert.Equal(0, TensorPrimitives.MinMagnitude([+0f, -0f])); + Assert.Equal(0, TensorPrimitives.MinMagnitude([-1, -0f])); + Assert.Equal(0, TensorPrimitives.MinMagnitude([-1, -0f, 1])); + } + + [Fact] + public static void Product_ThrowsForEmpty() + { + Assert.Throws(() => TensorPrimitives.Product(ReadOnlySpan.Empty)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Product(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + float f = x[0]; + for (int i = 1; i < x.Length; i++) + { + f *= x[i]; + } + + Assert.Equal(f, TensorPrimitives.Product(x), Tolerance); + } + + [Fact] + public static void Product_KnownValues() + { + Assert.Equal(1, TensorPrimitives.Product([1])); + Assert.Equal(-2, TensorPrimitives.Product([1, -2])); + Assert.Equal(-6, TensorPrimitives.Product([1, -2, 3])); + Assert.Equal(24, TensorPrimitives.Product([1, -2, 3, -4])); + Assert.Equal(120, TensorPrimitives.Product([1, -2, 3, -4, 5])); + Assert.Equal(-720, TensorPrimitives.Product([1, -2, 3, -4, 5, -6])); + Assert.Equal(0, TensorPrimitives.Product([1, -2, 3, -4, 5, -6, 0])); + Assert.Equal(0, TensorPrimitives.Product([0, 1, -2, 3, -4, 5, -6])); + Assert.Equal(0, TensorPrimitives.Product([1, -2, 3, 0, -4, 5, -6])); + Assert.Equal(float.NaN, TensorPrimitives.Product([1, -2, 3, float.NaN, -4, 5, -6])); + } + + [Fact] + public static void ProductOfDifferences_ThrowsForEmptyAndMismatchedLengths() + { + Assert.Throws(() => TensorPrimitives.ProductOfDifferences(ReadOnlySpan.Empty, ReadOnlySpan.Empty)); + Assert.Throws(() => TensorPrimitives.ProductOfDifferences(ReadOnlySpan.Empty, CreateTensor(1))); + Assert.Throws(() => TensorPrimitives.ProductOfDifferences(CreateTensor(1), ReadOnlySpan.Empty)); + Assert.Throws(() => TensorPrimitives.ProductOfDifferences(CreateTensor(44), CreateTensor(43))); + Assert.Throws(() => TensorPrimitives.ProductOfDifferences(CreateTensor(43), CreateTensor(44))); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void ProductOfDifferences(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + + float f = x[0] - y[0]; + for (int i = 1; i < x.Length; i++) + { + f *= x[i] - y[i]; + } + Assert.Equal(f, TensorPrimitives.ProductOfDifferences(x, y), Tolerance); + } + + [Fact] + public static void ProductOfDifferences_KnownValues() + { + Assert.Equal(0, TensorPrimitives.ProductOfDifferences([0], [0])); + Assert.Equal(0, TensorPrimitives.ProductOfDifferences([1], [1])); + Assert.Equal(1, TensorPrimitives.ProductOfDifferences([1], [0])); + Assert.Equal(-1, TensorPrimitives.ProductOfDifferences([0], [1])); + Assert.Equal(-1, TensorPrimitives.ProductOfDifferences([1, 2, 3, 4, 5], [2, 3, 4, 5, 6])); + Assert.Equal(120, TensorPrimitives.ProductOfDifferences([1, 2, 3, 4, 5], [0, 0, 0, 0, 0])); + Assert.Equal(-120, TensorPrimitives.ProductOfDifferences([0, 0, 0, 0, 0], [1, 2, 3, 4, 5])); + Assert.Equal(float.NaN, TensorPrimitives.ProductOfDifferences([1, 2, float.NaN, 4, 5], [0, 0, 0, 0, 0])); + } + + [Fact] + public static void ProductOfSums_ThrowsForEmptyAndMismatchedLengths() + { + Assert.Throws(() => TensorPrimitives.ProductOfSums(ReadOnlySpan.Empty, ReadOnlySpan.Empty)); + Assert.Throws(() => TensorPrimitives.ProductOfSums(ReadOnlySpan.Empty, CreateTensor(1))); + Assert.Throws(() => TensorPrimitives.ProductOfSums(CreateTensor(1), ReadOnlySpan.Empty)); + Assert.Throws(() => TensorPrimitives.ProductOfSums(CreateTensor(44), CreateTensor(43))); + Assert.Throws(() => TensorPrimitives.ProductOfSums(CreateTensor(43), CreateTensor(44))); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void ProductOfSums(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + + float f = x[0] + y[0]; + for (int i = 1; i < x.Length; i++) + { + f *= x[i] + y[i]; + } + Assert.Equal(f, TensorPrimitives.ProductOfSums(x, y), Tolerance); + } + + [Fact] + public static void ProductOfSums_KnownValues() + { + Assert.Equal(0, TensorPrimitives.ProductOfSums([0], [0])); + Assert.Equal(1, TensorPrimitives.ProductOfSums([0], [1])); + Assert.Equal(1, TensorPrimitives.ProductOfSums([1], [0])); + Assert.Equal(2, TensorPrimitives.ProductOfSums([1], [1])); + Assert.Equal(10395, TensorPrimitives.ProductOfSums([1, 2, 3, 4, 5], [2, 3, 4, 5, 6])); + Assert.Equal(120, TensorPrimitives.ProductOfSums([1, 2, 3, 4, 5], [0, 0, 0, 0, 0])); + Assert.Equal(120, TensorPrimitives.ProductOfSums([0, 0, 0, 0, 0], [1, 2, 3, 4, 5])); + Assert.Equal(float.NaN, TensorPrimitives.ProductOfSums([1, 2, float.NaN, 4, 5], [0, 0, 0, 0, 0])); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Sum(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Sum(MemoryMarshal.ToEnumerable(x.Memory)), TensorPrimitives.Sum(x), Tolerance); + + float sum = 0; + foreach (float f in x.Span) + { + sum += f; + } + Assert.Equal(sum, TensorPrimitives.Sum(x), Tolerance); + } + + [Fact] + public static void Sum_KnownValues() + { + Assert.Equal(0, TensorPrimitives.Sum([0])); + Assert.Equal(1, TensorPrimitives.Sum([0, 1])); + Assert.Equal(6, TensorPrimitives.Sum([1, 2, 3])); + Assert.Equal(0, TensorPrimitives.Sum([-3, 0, 3])); + Assert.Equal(float.NaN, TensorPrimitives.Sum([-3, float.NaN, 3])); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SumOfSquares(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Sum(MemoryMarshal.ToEnumerable(x.Memory), v => v * v), TensorPrimitives.SumOfSquares(x), Tolerance); + + float sum = 0; + foreach (float f in x.Span) + { + sum += f * f; + } + Assert.Equal(sum, TensorPrimitives.SumOfSquares(x), Tolerance); + } + + [Fact] + public static void SumOfSquares_KnownValues() + { + Assert.Equal(0, TensorPrimitives.SumOfSquares([0])); + Assert.Equal(1, TensorPrimitives.SumOfSquares([0, 1])); + Assert.Equal(14, TensorPrimitives.SumOfSquares([1, 2, 3])); + Assert.Equal(18, TensorPrimitives.SumOfSquares([-3, 0, 3])); + Assert.Equal(float.NaN, TensorPrimitives.SumOfSquares([-3, float.NaN, 3])); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void SumOfMagnitudes(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + + Assert.Equal(Enumerable.Sum(MemoryMarshal.ToEnumerable(x.Memory), MathF.Abs), TensorPrimitives.SumOfMagnitudes(x), Tolerance); + + float sum = 0; + foreach (float f in x.Span) + { + sum += MathF.Abs(f); + } + Assert.Equal(sum, TensorPrimitives.SumOfMagnitudes(x), Tolerance); + } + + [Fact] + public static void SumOfMagnitudes_KnownValues() + { + Assert.Equal(0, TensorPrimitives.SumOfMagnitudes([0])); + Assert.Equal(1, TensorPrimitives.SumOfMagnitudes([0, 1])); + Assert.Equal(6, TensorPrimitives.SumOfMagnitudes([1, 2, 3])); + Assert.Equal(6, TensorPrimitives.SumOfMagnitudes([-3, 0, 3])); + Assert.Equal(float.NaN, TensorPrimitives.SumOfMagnitudes([-3, float.NaN, 3])); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.netcore.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.netcore.cs new file mode 100644 index 00000000000000..113f26048d352c --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.netcore.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using Xunit; + +namespace System.Numerics.Tensors.Tests +{ + public static partial class TensorPrimitivesTests + { + [Theory] + [InlineData(0)] + [MemberData(nameof(TensorLengths))] + public static void ConvertToHalf(int tensorLength) + { + using BoundedMemory source = CreateAndFillTensor(tensorLength); + foreach (int destLength in new[] { source.Length, source.Length + 1 }) + { + Half[] destination = new Half[destLength]; + + TensorPrimitives.ConvertToHalf(source, destination); + + for (int i = 0; i < source.Length; i++) + { + Assert.Equal((Half)source[i], destination[i]); + } + + if (destination.Length > source.Length) + { + for (int i = source.Length; i < destination.Length; i++) + { + Assert.Equal(Half.Zero, destination[i]); + } + } + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void ConvertToHalf_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory source = CreateAndFillTensor(tensorLength); + Half[] destination = new Half[source.Length - 1]; + + AssertExtensions.Throws("destination", () => TensorPrimitives.ConvertToHalf(source, destination)); + } + + [Theory] + [InlineData(0)] + [MemberData(nameof(TensorLengths))] + public static void ConvertToSingle(int tensorLength) + { + Half[] source = new Half[tensorLength]; + for (int i = 0; i < source.Length; i++) + { + source[i] = (Half)s_random.NextSingle(); + } + + foreach (int destLength in new[] { source.Length, source.Length + 1 }) + { + using BoundedMemory destination = CreateTensor(destLength); + destination.Span.Fill(0f); + + TensorPrimitives.ConvertToSingle(source, destination); + + for (int i = 0; i < source.Length; i++) + { + Assert.Equal((float)source[i], destination[i]); + } + + if (destination.Length > source.Length) + { + for (int i = source.Length; i < destination.Length; i++) + { + Assert.Equal(0f, destination[i]); + } + } + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void ConvertToSingle_ThrowsForTooShortDestination(int tensorLength) + { + Half[] source = new Half[tensorLength]; + using BoundedMemory destination = CreateTensor(source.Length - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.ConvertToSingle(source, destination)); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorTemplate.ttinclude b/src/libraries/System.Numerics.Tensors/tests/TensorTemplate.ttinclude deleted file mode 100644 index 9448791a5db6c4..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorTemplate.ttinclude +++ /dev/null @@ -1,328 +0,0 @@ -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> -<#+ - public class TypeConfiguration - { - public TypeConfiguration(string typeName, string classPrefix = null, string oneLiteral = "1", string zeroLiteral = "0", bool supportsNumeric = true, bool supportsBitwise = true, IEnumerable unsupportedMethods = null) - { - TypeName = typeName; - ClassPrefix = classPrefix ?? char.ToUpper(typeName[0]) + typeName.Substring(1); - OneLiteral = oneLiteral; - ZeroLiteral = zeroLiteral; - SupportsNumeric = supportsNumeric; - SupportsBitwise = supportsBitwise; - UnsupportedMethods = new HashSet(unsupportedMethods ?? Enumerable.Empty()); - } - - public string TypeName { get; } - public string ClassPrefix { get; } - public string OneLiteral { get; } - public string ZeroLiteral { get; } - - public bool SupportsNumeric { get; } - public bool SupportsBitwise { get; } - public ISet UnsupportedMethods { get; } - } - - public string GenerateIfStatementHeader(TypeConfiguration type) - { - string keyword = (type == typeConfiguration[0]) ? "if" : "else if"; - return $"{keyword} (typeof(T) == typeof({type.TypeName}))"; - } - - public TypeConfiguration[] typeConfiguration = new [] - { - new TypeConfiguration("bool", oneLiteral:"true", zeroLiteral:"false", supportsNumeric: false, unsupportedMethods: new[] {"LeftShift", "RightShift"}), - new TypeConfiguration("byte"), - new TypeConfiguration("char", oneLiteral:"(char)1", zeroLiteral:"(char)0"), - new TypeConfiguration("decimal", supportsBitwise: false), - new TypeConfiguration("double", oneLiteral:"1.0", supportsBitwise: false), - new TypeConfiguration("float", oneLiteral:"1.0f", supportsBitwise: false), - new TypeConfiguration("int"), - new TypeConfiguration("long"), - new TypeConfiguration("sbyte", classPrefix:"SByte"), - new TypeConfiguration("short"), - new TypeConfiguration("uint", classPrefix:"UInt", unsupportedMethods: new[] {"UnaryMinus"}), - new TypeConfiguration("ulong", classPrefix:"ULong", unsupportedMethods: new[] {"UnaryMinus"}), - new TypeConfiguration("ushort", classPrefix:"UShort", unsupportedMethods: new[] {"UnaryMinus"}) - }; - - public enum MethodType - { - Unary, - UnaryInPlace, - BinaryScalar, - BinaryInt, - Binary, - Comparison, - Contraction - } - - public class MethodConfiguration - { - public MethodConfiguration(string methodName, MethodType methodType, string op = null, bool isNumeric = false, bool isBitwise = false) - { - MethodName = methodName; - MethodType = methodType; - Operator = op; - IsNumeric = isNumeric; - IsBitwise = isBitwise; - } - - public string ResultName => "result"; - - public string Op1Name - { - get - { - switch (MethodType) - { - case MethodType.Unary: - case MethodType.UnaryInPlace: - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - return "tensor"; - case MethodType.Binary: - case MethodType.Comparison: - case MethodType.Contraction: - return "left"; - default: - throw new ArgumentException(); - }; - } - } - - public string Op2Name - { - get - { - switch (MethodType) - { - case MethodType.BinaryScalar: - return "scalar"; - case MethodType.BinaryInt: - return "value"; - case MethodType.Binary: - case MethodType.Comparison: - case MethodType.Contraction: - return "right"; - case MethodType.Unary: - case MethodType.UnaryInPlace: - default: - throw new ArgumentException(); - }; - } - } - - public string MethodName { get; } - public MethodType MethodType { get; } - public string Operator { get; } - - public string GetGenericMethodSignature(string tensorType, string genericType) - { - var resultType = GetResultType(tensorType, genericType); - var arguments = GetMethodArguments(tensorType, genericType); - - return $"{resultType} {MethodName}<{genericType}>({arguments})"; - } - - public string GetGenericResultMethodSignature(string tensorType, string genericType) - { - var resultType = GetResultType(tensorType, genericType); - var arguments = GetMethodArguments(tensorType, genericType); - - return $"void {MethodName}<{genericType}>({arguments}, {resultType} {ResultName})"; - } - - public string GetResultMethodSignature(string tensorType, string genericType) - { - var resultType = GetResultType(tensorType, genericType); - var arguments = GetMethodArguments(tensorType, genericType); - - return $"void {MethodName}({arguments}, {resultType} {ResultName})"; - } - - public string GetMethodArguments(string tensorType, string genericType) - { - switch (MethodType) - { - case MethodType.Unary: - case MethodType.UnaryInPlace: - return $"{tensorType}<{genericType}> {Op1Name}"; - case MethodType.BinaryScalar: - return $"{tensorType}<{genericType}> {Op1Name}, {genericType} {Op2Name}"; - case MethodType.BinaryInt: - return $"{tensorType}<{genericType}> {Op1Name}, int {Op2Name}"; - case MethodType.Binary: - case MethodType.Comparison: - return $"{tensorType}<{genericType}> {Op1Name}, {tensorType}<{genericType}> {Op2Name}"; - case MethodType.Contraction: - return $"{tensorType}<{genericType}> {Op1Name}, {tensorType}<{genericType}> {Op2Name}, int[] leftAxes, int[] rightAxes"; - default: - throw new ArgumentException(); - } - } - - public string GetCallArguments() - { - switch (MethodType) - { - case MethodType.Unary: - case MethodType.UnaryInPlace: - return $"{Op1Name}"; - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - case MethodType.Binary: - case MethodType.Comparison: - return $"{Op1Name}, {Op2Name}"; - case MethodType.Contraction: - return "left, right, leftAxes, rightAxes"; - default: - throw new ArgumentException(); - } - } - - public string GetValidationMethod(bool includeResult) - { - var suffix = includeResult ? ", result" : ""; - switch (MethodType) - { - case MethodType.Unary: - case MethodType.UnaryInPlace: - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - return $"ValidateArgs({Op1Name}{suffix});"; - case MethodType.Binary: - case MethodType.Comparison: - return $"ValidateBinaryArgs({Op1Name}, {Op2Name}{suffix});"; - case MethodType.Contraction: - return $"var resultDimensions = ValidateContractArgs({Op1Name}, {Op2Name}, leftAxes, rightAxes{suffix});"; - default: - throw new ArgumentException(); - } - } - - public string GetResultType(string tensorType, string typeName) - { - switch (MethodType) - { - case MethodType.Unary: - case MethodType.UnaryInPlace: - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - case MethodType.Binary: - case MethodType.Contraction: - return $"{tensorType}<{typeName}>"; - case MethodType.Comparison: - return $"{tensorType}"; - default: - throw new ArgumentException(); - } - } - - public string GetLinearOperationCheck() - { - switch (MethodType) - { - case MethodType.Unary: - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - return $"({ResultName}.IsReversedStride == {Op1Name}.IsReversedStride)"; - case MethodType.Binary: - case MethodType.Comparison: - return $"(({ResultName}.IsReversedStride == {Op1Name}.IsReversedStride) && ({ResultName}.IsReversedStride == {Op2Name}.IsReversedStride))"; - case MethodType.UnaryInPlace: - default: - throw new ArgumentException(); - } - } - - - public string GetElementOperation(string typeName, string access) - { - return GetElementOperation(typeName, access, access, access); - } - - public string GetElementOperation(string typeName, string resultAccess, string leftAccess, string rightAccess) - { - switch (MethodType) - { - case MethodType.Unary: - return $"{ResultName}{resultAccess} = ({typeName}){Operator}{Op1Name}{leftAccess}"; - case MethodType.UnaryInPlace: - return $"{ResultName}{resultAccess}{Operator}"; - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - return $"{ResultName}{resultAccess} = ({typeName})({Op1Name}{leftAccess} {Operator} {Op2Name})"; - case MethodType.Binary: - return $"{ResultName}{resultAccess} = ({typeName})({Op1Name}{leftAccess} {Operator} {Op2Name}{rightAccess})"; - case MethodType.Comparison: - return $"{ResultName}{resultAccess} = {Op1Name}{leftAccess} {Operator} {Op2Name}{rightAccess}"; - default: - throw new ArgumentException(); - - } - } - - public string InitializeResult(string typeName) - { - switch (MethodType) - { - case MethodType.UnaryInPlace: - return $"{Op1Name}.Clone()"; - case MethodType.Unary: - case MethodType.BinaryScalar: - case MethodType.BinaryInt: - case MethodType.Binary: - return $"{Op1Name}.CloneEmpty()"; - case MethodType.Comparison: - return $"{Op1Name}.CloneEmpty()"; - case MethodType.Contraction: - return $"{Op1Name}.CloneEmpty(resultDimensions)"; - default: - throw new ArgumentException(); - } - } - - public bool IsNumeric { get; } - public bool IsBitwise { get; } - } - - - public MethodConfiguration[] methodConfiguration = new [] - { - new MethodConfiguration("Add", MethodType.Binary, "+", isNumeric:true), - new MethodConfiguration("Add", MethodType.BinaryScalar, "+", isNumeric:true), - new MethodConfiguration("UnaryPlus", MethodType.Unary, "+", isNumeric:true), - new MethodConfiguration("Subtract", MethodType.Binary, "-", isNumeric:true), - new MethodConfiguration("Subtract", MethodType.BinaryScalar, "-", isNumeric:true), - new MethodConfiguration("UnaryMinus", MethodType.Unary, "-", isNumeric:true), - new MethodConfiguration("Increment", MethodType.UnaryInPlace, "++", isNumeric:true), - new MethodConfiguration("Decrement", MethodType.UnaryInPlace, "--", isNumeric:true), - new MethodConfiguration("Multiply", MethodType.Binary, "*", isNumeric:true), // element-wise product, not matrix product - new MethodConfiguration("Multiply", MethodType.BinaryScalar, "*", isNumeric:true), - new MethodConfiguration("Divide", MethodType.Binary, "/", isNumeric:true), - new MethodConfiguration("Divide", MethodType.BinaryScalar, "/", isNumeric:true), - new MethodConfiguration("Modulo", MethodType.Binary, "%", isNumeric:true), - new MethodConfiguration("Modulo", MethodType.BinaryScalar, "%", isNumeric:true), - new MethodConfiguration("And", MethodType.Binary, "&", isBitwise: true), - new MethodConfiguration("And", MethodType.BinaryScalar, "&", isBitwise: true), - new MethodConfiguration("Or", MethodType.Binary, "|", isBitwise: true), - new MethodConfiguration("Or", MethodType.BinaryScalar, "|", isBitwise: true), - new MethodConfiguration("Xor", MethodType.Binary, "^", isBitwise: true), - new MethodConfiguration("Xor", MethodType.BinaryScalar, "^", isBitwise: true), - new MethodConfiguration("LeftShift", MethodType.BinaryInt, "<<", isBitwise: true), - new MethodConfiguration("RightShift", MethodType.BinaryInt, ">>", isBitwise: true), - - // Note all of these are element-wise operations not testing the operation on the entire Tensor - new MethodConfiguration("Equals", MethodType.Comparison, "=="), - new MethodConfiguration("NotEquals", MethodType.Comparison, "!="), - new MethodConfiguration("GreaterThanOrEqual", MethodType.Comparison, ">=", isNumeric:true), - new MethodConfiguration("LessThanOrEqual", MethodType.Comparison, "<=", isNumeric:true), - new MethodConfiguration("GreaterThan", MethodType.Comparison, ">", isNumeric:true), - new MethodConfiguration("LessThan", MethodType.Comparison, "<", isNumeric:true), - - new MethodConfiguration("Contract", MethodType.Contraction, isNumeric:true), - }.OrderBy(m => m.MethodName).ToArray(); -#> diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs deleted file mode 100644 index 27c7ba75e4e259..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorTests.cs +++ /dev/null @@ -1,2486 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace System.Numerics.Tensors.Tests -{ - public class TensorTests : TensorTestsBase - { - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ConstructTensorFromArrayRank1(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray(new[] { 0, 1, 2 }); - - Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - Assert.Equal(0, tensor[0]); - Assert.Equal(1, tensor[1]); - Assert.Equal(2, tensor[2]); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ConstructTensorFromArrayRank2(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray(new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - Assert.Equal(0, tensor[0, 0]); - Assert.Equal(1, tensor[0, 1]); - Assert.Equal(2, tensor[0, 2]); - Assert.Equal(3, tensor[1, 0]); - Assert.Equal(4, tensor[1, 1]); - Assert.Equal(5, tensor[1, 2]); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ConstructTensorFromArrayRank3(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray(new[, ,] - { - { - {0, 1, 2}, - {3, 4, 5} - }, - { - {6, 7 ,8 }, - {9, 10 ,11 }, - }, - { - {12, 13 ,14 }, - {15, 16 ,17 }, - }, - { - {18, 19 ,20 }, - {21, 22 ,23 }, - } - }); - - Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - - Assert.Equal(0, tensor[0, 0, 0]); - Assert.Equal(1, tensor[0, 0, 1]); - Assert.Equal(2, tensor[0, 0, 2]); - Assert.Equal(3, tensor[0, 1, 0]); - Assert.Equal(4, tensor[0, 1, 1]); - Assert.Equal(5, tensor[0, 1, 2]); - - Assert.Equal(6, tensor[1, 0, 0]); - Assert.Equal(7, tensor[1, 0, 1]); - Assert.Equal(8, tensor[1, 0, 2]); - Assert.Equal(9, tensor[1, 1, 0]); - Assert.Equal(10, tensor[1, 1, 1]); - Assert.Equal(11, tensor[1, 1, 2]); - - Assert.Equal(12, tensor[2, 0, 0]); - Assert.Equal(13, tensor[2, 0, 1]); - Assert.Equal(14, tensor[2, 0, 2]); - Assert.Equal(15, tensor[2, 1, 0]); - Assert.Equal(16, tensor[2, 1, 1]); - Assert.Equal(17, tensor[2, 1, 2]); - - Assert.Equal(18, tensor[3, 0, 0]); - Assert.Equal(19, tensor[3, 0, 1]); - Assert.Equal(20, tensor[3, 0, 2]); - Assert.Equal(21, tensor[3, 1, 0]); - Assert.Equal(22, tensor[3, 1, 1]); - Assert.Equal(23, tensor[3, 1, 2]); - } - - [Fact] - public void ConstructDenseTensorFromPointer() - { - using (var nativeMemory = NativeMemoryFromArray(Enumerable.Range(0, 24).ToArray())) - { - var dimensions = new[] { 4, 2, 3 }; - var tensor = new DenseTensor(nativeMemory.Memory, dimensions, false); - - Assert.Equal(0, tensor[0, 0, 0]); - Assert.Equal(1, tensor[0, 0, 1]); - Assert.Equal(2, tensor[0, 0, 2]); - Assert.Equal(3, tensor[0, 1, 0]); - Assert.Equal(4, tensor[0, 1, 1]); - Assert.Equal(5, tensor[0, 1, 2]); - - Assert.Equal(6, tensor[1, 0, 0]); - Assert.Equal(7, tensor[1, 0, 1]); - Assert.Equal(8, tensor[1, 0, 2]); - Assert.Equal(9, tensor[1, 1, 0]); - Assert.Equal(10, tensor[1, 1, 1]); - Assert.Equal(11, tensor[1, 1, 2]); - - Assert.Equal(12, tensor[2, 0, 0]); - Assert.Equal(13, tensor[2, 0, 1]); - Assert.Equal(14, tensor[2, 0, 2]); - Assert.Equal(15, tensor[2, 1, 0]); - Assert.Equal(16, tensor[2, 1, 1]); - Assert.Equal(17, tensor[2, 1, 2]); - - Assert.Equal(18, tensor[3, 0, 0]); - Assert.Equal(19, tensor[3, 0, 1]); - Assert.Equal(20, tensor[3, 0, 2]); - Assert.Equal(21, tensor[3, 1, 0]); - Assert.Equal(22, tensor[3, 1, 1]); - Assert.Equal(23, tensor[3, 1, 2]); - } - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ConstructSparseTensor(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray(new[,] - { - {0, 0, 0, 0}, - {5, 8, 0, 0}, - {0, 0, 3, 0}, - {0, 6, 0, 0} - }); - - Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - - - Assert.Equal(0, tensor[0, 0]); - Assert.Equal(0, tensor[0, 1]); - Assert.Equal(0, tensor[0, 2]); - Assert.Equal(0, tensor[0, 3]); - - - Assert.Equal(5, tensor[1, 0]); - Assert.Equal(8, tensor[1, 1]); - Assert.Equal(0, tensor[1, 2]); - Assert.Equal(0, tensor[1, 3]); - - - Assert.Equal(0, tensor[2, 0]); - Assert.Equal(0, tensor[2, 1]); - Assert.Equal(3, tensor[2, 2]); - Assert.Equal(0, tensor[2, 3]); - - - Assert.Equal(0, tensor[3, 0]); - Assert.Equal(6, tensor[3, 1]); - Assert.Equal(0, tensor[3, 2]); - Assert.Equal(0, tensor[3, 3]); - - if (tensorConstructor.TensorType == TensorType.CompressedSparse) - { - var compressedSparseTensor = (CompressedSparseTensor)tensor; - - Assert.Equal(4, compressedSparseTensor.NonZeroCount); - - int[] expectedValues, expectedCompressedCounts, expectedIndices; - - if (compressedSparseTensor.IsReversedStride) - { - // csc - expectedValues = new[] { 5, 8, 6, 3 }; - expectedCompressedCounts = new[] { 0, 1, 3, 4, 4 }; - expectedIndices = new[] { 1, 1, 3, 2 }; - } - else - { - // csr - expectedValues = new[] { 5, 8, 3, 6 }; - expectedCompressedCounts = new[] { 0, 0, 2, 3, 4 }; - expectedIndices = new[] { 0, 1, 2, 1 }; - } - Assert.Equal(expectedValues, compressedSparseTensor.Values.Slice(0, compressedSparseTensor.NonZeroCount).ToArray()); - Assert.Equal(expectedCompressedCounts, compressedSparseTensor.CompressedCounts.ToArray()); - Assert.Equal(expectedIndices, compressedSparseTensor.Indices.Slice(0, compressedSparseTensor.NonZeroCount).ToArray()); - } - } - - [Theory()] - [InlineData(false)] - [InlineData(true)] - public void ConstructCompressedSparseTensorFromPointers(bool isReversedStride) - { - int[] values, compressedCounts, indices; - if (isReversedStride) - { - // csc - values = new[] { 5, 8, 6, 3 }; - compressedCounts = new[] { 0, 1, 3, 4, 4 }; - indices = new[] { 1, 1, 3, 2 }; - } - else - { - // csr - values = new[] { 5, 8, 3, 6 }; - compressedCounts = new[] { 0, 0, 2, 3, 4 }; - indices = new[] { 0, 1, 2, 1 }; - } - int[] dimensions = new[] { 4, 4 }; - - using (var valuesMemory = NativeMemoryFromArray(values)) - using (var compressedCountsMemory = NativeMemoryFromArray(compressedCounts)) - using (var indicesMemory = NativeMemoryFromArray(indices)) - { - var tensor = new CompressedSparseTensor(valuesMemory.Memory, - compressedCountsMemory.Memory, - indicesMemory.Memory, - values.Length, - dimensions, - isReversedStride); - - Assert.Equal(0, tensor[0, 0]); - Assert.Equal(0, tensor[0, 1]); - Assert.Equal(0, tensor[0, 2]); - Assert.Equal(0, tensor[0, 3]); - - - Assert.Equal(5, tensor[1, 0]); - Assert.Equal(8, tensor[1, 1]); - Assert.Equal(0, tensor[1, 2]); - Assert.Equal(0, tensor[1, 3]); - - - Assert.Equal(0, tensor[2, 0]); - Assert.Equal(0, tensor[2, 1]); - Assert.Equal(3, tensor[2, 2]); - Assert.Equal(0, tensor[2, 3]); - - - Assert.Equal(0, tensor[3, 0]); - Assert.Equal(6, tensor[3, 1]); - Assert.Equal(0, tensor[3, 2]); - Assert.Equal(0, tensor[3, 3]); - } - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ConstructFromDimensions(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromDimensions(new[] { 2, 3, 4 }); - Assert.Equal(3, tensor.Rank); - Assert.Equal(3, tensor.Dimensions.Length); - Assert.Equal(2, tensor.Dimensions[0]); - Assert.Equal(3, tensor.Dimensions[1]); - Assert.Equal(4, tensor.Dimensions[2]); - Assert.Equal(24, tensor.Length); - Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - - //Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: null)); - Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: new int[0])); - - Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: new[] { 1, 0 })); - Assert.Throws("dimensions", () => tensorConstructor.CreateFromDimensions(dimensions: new[] { 1, -1 })); - - // ensure dimensions are immutable - var dimensions = new[] { 1, 2, 3 }; - tensor = tensorConstructor.CreateFromDimensions(dimensions: dimensions); - dimensions[0] = dimensions[1] = dimensions[2] = 0; - Assert.Equal(1, tensor.Dimensions[0]); - Assert.Equal(2, tensor.Dimensions[1]); - Assert.Equal(3, tensor.Dimensions[2]); - } - - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNonZeroLowerBoundArraySupported))] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ConstructTensorFromArrayRank3WithLowerBounds(TensorConstructor tensorConstructor) - { - var dimensions = new[] { 2, 3, 4 }; - var lowerBounds = new[] { 0, 5, 200 }; - var arrayWithLowerBounds = Array.CreateInstance(typeof(int), dimensions, lowerBounds); - - int value = 0; - for (int x = lowerBounds[0]; x < lowerBounds[0] + dimensions[0]; x++) - { - for (int y = lowerBounds[1]; y < lowerBounds[1] + dimensions[1]; y++) - { - for (int z = lowerBounds[2]; z < lowerBounds[2] + dimensions[2]; z++) - { - arrayWithLowerBounds.SetValue(value++, x, y, z); - } - } - } - - var tensor = tensorConstructor.CreateFromArray(arrayWithLowerBounds); - - var expected = tensorConstructor.CreateFromArray(new[, ,] - { - { - { 0, 1, 2, 3 }, - { 4, 5, 6, 7 }, - { 8, 9, 10, 11 } - }, - { - { 12, 13, 14, 15 }, - { 16, 17, 18, 19 }, - { 20, 21, 22, 23 } - } - } - ); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(expected, tensor)); - Assert.Equal(tensorConstructor.IsReversedStride, tensor.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void StructurallyEqualTensor(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var arr = new[, ,] - { - { - {0, 1, 2}, - {3, 4, 5} - }, - { - {6, 7 ,8 }, - {9, 10 ,11 }, - }, - { - {12, 13 ,14 }, - {15, 16 ,17 }, - }, - { - {18, 19 ,20 }, - {21, 22 ,23 }, - } - }; - var tensor = leftConstructor.CreateFromArray(arr); - var tensor2 = rightConstructor.CreateFromArray(arr); - - Assert.Equal(0, StructuralComparisons.StructuralComparer.Compare(tensor, tensor2)); - Assert.Equal(0, StructuralComparisons.StructuralComparer.Compare(tensor2, tensor)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor, tensor2)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor2, tensor)); - // Issue: should Tensors with different layout be structurally equal? - if (leftConstructor.IsReversedStride == leftConstructor.IsReversedStride) - { - Assert.Equal(StructuralComparisons.StructuralEqualityComparer.GetHashCode(tensor), StructuralComparisons.StructuralEqualityComparer.GetHashCode(tensor2)); - } - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void StructurallyEqualArray(TensorConstructor tensorConstructor) - { - var arr = new[, ,] - { - { - {0, 1, 2}, - {3, 4, 5} - }, - { - {6, 7 ,8 }, - {9, 10 ,11 }, - }, - { - {12, 13 ,14 }, - {15, 16 ,17 }, - }, - { - {18, 19 ,20 }, - {21, 22 ,23 }, - } - }; - var tensor = tensorConstructor.CreateFromArray(arr); - - Assert.Equal(0, StructuralComparisons.StructuralComparer.Compare(tensor, arr)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor, arr)); - - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetDiagonalSquare(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var diag = tensor.GetDiagonal(); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 1, 3, 5 })); - diag = tensor.GetDiagonal(1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 2, 9 })); - diag = tensor.GetDiagonal(2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 4 })); - Assert.Throws("offset", () => tensor.GetDiagonal(3)); - - diag = tensor.GetDiagonal(-1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 8, 7 })); - diag = tensor.GetDiagonal(-2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 1 })); - Assert.Throws("offset", () => tensor.GetDiagonal(-3)); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetDiagonalRectangle(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 4, 3, 7 }, - { 8, 3, 9, 2, 6 }, - { 1, 7, 5, 2, 9 } - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var diag = tensor.GetDiagonal(); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 1, 3, 5 })); - diag = tensor.GetDiagonal(1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 2, 9, 2 })); - diag = tensor.GetDiagonal(2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 4, 2, 9 })); - diag = tensor.GetDiagonal(3); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 3, 6 })); - diag = tensor.GetDiagonal(4); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 7 })); - Assert.Throws("offset", () => tensor.GetDiagonal(5)); - - diag = tensor.GetDiagonal(-1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 8, 7 })); - diag = tensor.GetDiagonal(-2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, new[] { 1 })); - Assert.Throws("offset", () => tensor.GetDiagonal(-3)); - Assert.Throws("offset", () => tensor.GetDiagonal(-4)); - Assert.Throws("offset", () => tensor.GetDiagonal(-5)); - } - - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetDiagonalCube(TensorConstructor tensorConstructor) - { - var arr = new[, ,] - { - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }, - { - { 4, 5, 7 }, - { 1, 6, 2 }, - { 3, 0, 8 }, - }, - { - { 5, 6, 1 }, - { 2, 2, 3 }, - { 4, 9, 4 }, - }, - - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var diag = tensor.GetDiagonal(); - var expected = new[,] - { - { 1, 2, 4 }, - { 1, 6, 2 }, - { 4, 9, 4 } - }; - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(diag, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, diag.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetTriangleSquare(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var tri = tensor.GetTriangle(0); - Assert.Equal(tensorConstructor.IsReversedStride, tri.IsReversedStride); - - var expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 0, 0 }, - { 8, 3, 0 }, - { 1, 7, 5 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 0 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(2); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetTriangle(3); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetTriangle(200); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetTriangle(-1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0 }, - { 8, 0, 0 }, - { 1, 7, 0 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(-2); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 1, 0, 0 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - }); - tri = tensor.GetTriangle(-3); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - // same as -3, should it be an exception? - tri = tensor.GetTriangle(-4); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(-300); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetTriangleRectangle(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 4, 3, 7 }, - { 8, 3, 9, 2, 6 }, - { 1, 7, 5, 2, 9 } - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var tri = tensor.GetTriangle(0); - var expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 0, 0, 0, 0 }, - { 8, 3, 0, 0, 0 }, - { 1, 7, 5, 0, 0 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, tri.IsReversedStride); - - tri = tensor.GetTriangle(1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 0, 0, 0 }, - { 8, 3, 9, 0, 0 }, - { 1, 7, 5, 2, 0 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(2); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4, 0, 0 }, - { 8, 3, 9, 2, 0 }, - { 1, 7, 5, 2, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(3); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4, 3, 0 }, - { 8, 3, 9, 2, 6 }, - { 1, 7, 5, 2, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetTriangle(4); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4, 3, 7 }, - { 8, 3, 9, 2, 6 }, - { 1, 7, 5, 2, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - // same as 4, should it be an exception? - tri = tensor.GetTriangle(5); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(1000); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetTriangle(-1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0, 0, 0 }, - { 8, 0, 0, 0, 0 }, - { 1, 7, 0, 0, 0 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 }, - { 1, 0, 0, 0, 0 } - }); - tri = tensor.GetTriangle(-2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 } - }); - tri = tensor.GetTriangle(-3); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetTriangle(-4); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(-5); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetTriangle(-100); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetTriangleCube(TensorConstructor tensorConstructor) - { - var arr = new[, ,] - { - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }, - { - { 4, 5, 7 }, - { 1, 6, 2 }, - { 3, 0, 8 }, - }, - { - { 5, 6, 1 }, - { 2, 2, 3 }, - { 4, 9, 4 }, - }, - - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var tri = tensor.GetTriangle(0); - var expected = tensorConstructor.CreateFromArray(new[, ,] - { - { - { 1, 2, 4 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - }, - { - { 4, 5, 7 }, - { 1, 6, 2 }, - { 0, 0, 0 }, - }, - { - { 5, 6, 1 }, - { 2, 2, 3 }, - { 4, 9, 4 }, - }, - - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, tri.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetUpperTriangleSquare(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var tri = tensor.GetUpperTriangle(0); - - var expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4 }, - { 0, 3, 9 }, - { 0, 0, 5 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, tri.IsReversedStride); - - tri = tensor.GetUpperTriangle(1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 2, 4 }, - { 0, 0, 9 }, - { 0, 0, 0 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(2); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 4 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(3); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(4); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(42); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(-1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 0, 7, 5 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(-2); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(-3); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(-300); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetUpperTriangleRectangle(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 4, 3, 7 }, - { 8, 3, 9, 2, 6 }, - { 1, 7, 5, 2, 9 } - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var tri = tensor.GetUpperTriangle(0); - var expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4, 3, 7 }, - { 0, 3, 9, 2, 6 }, - { 0, 0, 5, 2, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, tri.IsReversedStride); - tri = tensor.GetUpperTriangle(1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 2, 4, 3, 7 }, - { 0, 0, 9, 2, 6 }, - { 0, 0, 0, 2, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(2); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 4, 3, 7 }, - { 0, 0, 0, 2, 6 }, - { 0, 0, 0, 0, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(3); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0, 3, 7 }, - { 0, 0, 0, 0, 6 }, - { 0, 0, 0, 0, 0 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(4); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0, 0, 7 }, - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - expected = tensorConstructor.CreateFromArray(new[,] - { - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0 } - }); - tri = tensor.GetUpperTriangle(5); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(6); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(1000); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(-1); - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4, 3, 7 }, - { 8, 3, 9, 2, 6 }, - { 0, 7, 5, 2, 9 } - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - expected = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 4, 3, 7 }, - { 8, 3, 9, 2, 6 }, - { 1, 7, 5, 2, 9 } - }); - tri = tensor.GetUpperTriangle(-2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - - tri = tensor.GetUpperTriangle(-3); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(-4); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - tri = tensor.GetUpperTriangle(-100); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetUpperTriangleCube(TensorConstructor tensorConstructor) - { - var arr = new[, ,] - { - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }, - { - { 4, 5, 7 }, - { 1, 6, 2 }, - { 3, 0, 8 }, - }, - { - { 5, 6, 1 }, - { 2, 2, 3 }, - { 4, 9, 4 }, - }, - - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var tri = tensor.GetUpperTriangle(0); - var expected = tensorConstructor.CreateFromArray(new[, ,] - { - { - { 1, 2, 4 }, - { 8, 3, 9 }, - { 1, 7, 5 }, - }, - { - { 0, 0, 0 }, - { 1, 6, 2 }, - { 3, 0, 8 }, - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 4, 9, 4 }, - }, - - }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tri, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, tri.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void Reshape(TensorConstructor tensorConstructor) - { - var arr = new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 } - }; - - var tensor = tensorConstructor.CreateFromArray(arr); - var actual = tensor.Reshape(new[] { 3, 2 }); - - var expected = tensorConstructor.IsReversedStride ? - new[,] - { - { 1, 5 }, - { 4, 3 }, - { 2, 6 } - } : - new[,] - { - { 1, 2 }, - { 3, 4 }, - { 5, 6 } - }; - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Fact] - public void Identity() - { - var actual = Tensor.CreateIdentity(3); - - var expected = new[,] - { - {1.0, 0, 0 }, - {0, 1.0, 0 }, - {0, 0, 1.0 } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void CreateWithDiagonal(TensorConstructor tensorConstructor) - { - var diagonal = tensorConstructor.CreateFromArray(new[] { 1, 2, 3, 4, 5 }); - var actual = Tensor.CreateFromDiagonal(diagonal); - - var expected = new[,] - { - {1, 0, 0, 0, 0 }, - {0, 2, 0, 0, 0 }, - {0, 0, 3, 0, 0 }, - {0, 0, 0, 4, 0 }, - {0, 0, 0, 0, 5 } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void CreateWithDiagonal3D(TensorConstructor tensorConstructor) - { - var diagonal = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 3, 4, 5 }, - { 1, 2, 3, 4, 5 }, - { 1, 2, 3, 4, 5 } - }); - var actual = Tensor.CreateFromDiagonal(diagonal); - var expected = new[, ,] - { - { - {1, 2, 3, 4, 5 }, - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 } - }, - { - {0, 0, 0, 0, 0 }, - {1, 2, 3, 4, 5 }, - {0, 0, 0, 0, 0 } - }, - { - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 }, - {1, 2, 3, 4, 5 } - } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void CreateWithDiagonalAndOffset(TensorConstructor tensorConstructor) - { - var diagonal = tensorConstructor.CreateFromArray(new[] { 1, 2, 3, 4 }); - var actual = Tensor.CreateFromDiagonal(diagonal, 1); - - var expected = new[,] - { - {0, 1, 0, 0, 0 }, - {0, 0, 2, 0, 0 }, - {0, 0, 0, 3, 0 }, - {0, 0, 0, 0, 4 }, - {0, 0, 0, 0, 0 } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - diagonal = tensorConstructor.CreateFromArray(new[] { 1, 2, 3, 4 }); - actual = Tensor.CreateFromDiagonal(diagonal, -1); - - expected = new[,] - { - {0, 0, 0, 0, 0 }, - {1, 0, 0, 0, 0 }, - {0, 2, 0, 0, 0 }, - {0, 0, 3, 0, 0 }, - {0, 0, 0, 4, 0 } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - diagonal = tensorConstructor.CreateFromArray(new[] { 1 }); - actual = Tensor.CreateFromDiagonal(diagonal, -4); - expected = new[,] - { - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 }, - {1, 0, 0, 0, 0 } - }; - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - diagonal = tensorConstructor.CreateFromArray(new[] { 1 }); - actual = Tensor.CreateFromDiagonal(diagonal, 4); - expected = new[,] - { - {0, 0, 0, 0, 1 }, - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 }, - {0, 0, 0, 0, 0 } - }; - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void CreateWithDiagonalAndOffset3D(TensorConstructor tensorConstructor) - { - var diagonal = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 3 }, - { 1, 2, 3 }, - { 1, 2, 3 } - }); - var actual = Tensor.CreateFromDiagonal(diagonal, 1); - - var expected = new[, ,] - { - { - { 0, 0, 0 }, - { 1, 2, 3 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 1, 2, 3 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 1, 2, 3 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - diagonal = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 3 }, - { 1, 2, 3 }, - { 1, 2, 3 } - }); - actual = Tensor.CreateFromDiagonal(diagonal, -1); - - expected = new[, ,] - { - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 1, 2, 3 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 1, 2, 3 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 1, 2, 3 }, - { 0, 0, 0 } - } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - diagonal = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 3 } - }); - actual = Tensor.CreateFromDiagonal(diagonal, 3); - - expected = new[, ,] - { - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 1, 2, 3 }, - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - diagonal = tensorConstructor.CreateFromArray(new[,] - { - { 1, 2, 3 } - }); - actual = Tensor.CreateFromDiagonal(diagonal, -3); - - expected = new[, ,] - { - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - }, - { - { 1, 2, 3 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 } - } - }; - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Add(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - var right = rightConstructor.CreateFromArray( - new[,] - { - { 6, 7 ,8 }, - { 9, 10 ,11 }, - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - { 6, 8, 10 }, - { 12, 14, 16 }, - }); - - var actual = TensorOperations.Add(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void AddScalar(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 }, - }); - - var actual = TensorOperations.Add(tensor, 1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void UnaryPlus(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensor; - - var actual = TensorOperations.UnaryPlus(tensor); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.False(ReferenceEquals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Subtract(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - var right = rightConstructor.CreateFromArray( - new[,] - { - { 6, 7 ,8 }, - { 9, 10 ,11 }, - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - { -6, -6, -6 }, - { -6, -6, -6}, - }); - - var actual = TensorOperations.Subtract(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void SubtractScalar(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - var expected = tensorConstructor.CreateFromArray( - new[,] - { - { -1, 0, 1 }, - { 2, 3, 4 }, - }); - - var actual = TensorOperations.Subtract(tensor, 1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void UnaryMinus(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, -1, -2}, - {-3, -4, -5} - }); - - var actual = TensorOperations.UnaryMinus(tensor); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.False(ReferenceEquals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void PrefixIncrement(TensorConstructor tensorConstructor) - { - Tensor tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expectedResult = tensorConstructor.CreateFromArray( - new[,] - { - {1, 2, 3}, - {4, 5, 6} - }); - - var expectedTensor = expectedResult; - - tensor = TensorOperations.Increment(tensor); - var actual = tensor; - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expectedResult)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor, expectedTensor)); - Assert.True(ReferenceEquals(tensor, actual)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void PostfixIncrement(TensorConstructor tensorConstructor) - { - Tensor tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - // returns original value - var expectedResult = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - // increments operand - var expectedTensor = tensorConstructor.CreateFromArray( - new[,] - { - {1, 2, 3}, - {4, 5, 6} - }); - - var actual = tensor; - tensor = TensorOperations.Increment(tensor); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expectedResult)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor, expectedTensor)); - Assert.False(ReferenceEquals(tensor, actual)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void PrefixDecrement(TensorConstructor tensorConstructor) - { - Tensor tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expectedResult = tensorConstructor.CreateFromArray( - new[,] - { - {-1, 0, 1}, - {2, 3, 4} - }); - - var expectedTensor = expectedResult; - - tensor = TensorOperations.Decrement(tensor); - var actual = tensor; - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expectedResult)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor, expectedTensor)); - Assert.True(ReferenceEquals(tensor, actual)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void PostfixDecrement(TensorConstructor tensorConstructor) - { - Tensor tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - // returns original value - var expectedResult = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - // decrements operand - var expectedTensor = tensorConstructor.CreateFromArray( - new[,] - { - {-1, 0, 1}, - {2, 3, 4} - }); - - var actual = tensor; - tensor = TensorOperations.Decrement(tensor); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expectedResult)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(tensor, expectedTensor)); - Assert.False(ReferenceEquals(tensor, actual)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Multiply(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - var right = rightConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 4}, - {9, 16, 25} - }); - - var actual = TensorOperations.Multiply(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void MultiplyScalar(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, 2, 4}, - {6, 8, 10} - }); - - var actual = TensorOperations.Multiply(tensor, 2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Divide(TensorConstructor dividendConstructor, TensorConstructor divisorConstructor) - { - var dividend = dividendConstructor.CreateFromArray( - new[,] - { - {0, 1, 4}, - {9, 16, 25} - }); - - var divisor = divisorConstructor.CreateFromArray( - new[,] - { - {1, 1, 2}, - {3, 4, 5} - }); - - var expected = divisorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var actual = TensorOperations.Divide(dividend, divisor); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(dividendConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void DivideScalar(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 2, 4}, - {6, 8, 10} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var actual = TensorOperations.Divide(tensor, 2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Modulo(TensorConstructor dividendConstructor, TensorConstructor divisorConstructor) - { - var dividend = dividendConstructor.CreateFromArray( - new[,] - { - {0, 3, 8}, - {11, 14, 17} - }); - - var divisor = divisorConstructor.CreateFromArray( - new[,] - { - {1, 2, 3}, - {4, 5, 6} - }); - - var expected = dividendConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var actual = TensorOperations.Modulo(dividend, divisor); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(dividendConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void ModuloScalar(TensorConstructor tensorConstructor) - { - var tensor = tensorConstructor.CreateFromArray( - new[,] - { - {0, 3, 4}, - {7, 8, 9} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 0}, - {1, 0, 1} - }); - - var actual = TensorOperations.Modulo(tensor, 2); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void And(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 3}, - {7, 15, 31} - }); - - var right = rightConstructor.CreateFromArray( - new[,] - { - {1, 1, 3}, - {2, 4, 8} - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 3}, - {2, 4, 8} - }); - - var actual = TensorOperations.And(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void AndScalar(TensorConstructor tensorConstructor) - { - var left = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 3}, - {5, 15, 31} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, 0, 0}, - {4, 4, 20} - }); - - var actual = TensorOperations.And(left, 20); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Or(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 3}, - {7, 14, 31} - }); - - var right = rightConstructor.CreateFromArray( - new[,] - { - {1, 2, 4}, - {2, 4, 8} - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - {1, 3, 7}, - {7, 14, 31} - }); - - var actual = TensorOperations.Or(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void OrScalar(TensorConstructor tensorConstructor) - { - var left = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {1, 1, 3}, - {3, 5, 5} - }); - - var actual = TensorOperations.Or(left, 1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void Xor(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 3}, - {7, 14, 31} - }); - - var right = rightConstructor.CreateFromArray( - new[,] - { - {1, 2, 4}, - {2, 4, 8} - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - {1, 3, 7}, - {5, 10, 23} - }); - - var actual = TensorOperations.Xor(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void XorScalar(TensorConstructor tensorConstructor) - { - var left = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {1, 0, 3}, - {2, 5, 4} - }); - - var actual = TensorOperations.Xor(left, 1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void LeftShift(TensorConstructor tensorConstructor) - { - var left = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, 2, 4}, - {6, 8, 10} - }); - - var actual = TensorOperations.LeftShift(left, 1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetSingleTensorConstructors))] - public void RightShift(TensorConstructor tensorConstructor) - { - var left = tensorConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var expected = tensorConstructor.CreateFromArray( - new[,] - { - {0, 0, 1}, - {1, 2, 2} - }); - - var actual = TensorOperations.RightShift(left, 1); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(tensorConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void ElementWiseEquals(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - var right = rightConstructor.CreateFromArray( - new[,] - { - {0, 1, -2}, - {2, 3, 5} - }); - - var expected = new[,] - { - {true, true, false }, - {false, false, true} - }.ToTensor(); - - var actual = TensorOperations.Equals(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory()] - [MemberData(nameof(GetDualTensorConstructors))] - public void ElementWiseNotEquals(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - var right = rightConstructor.CreateFromArray( - new[,] - { - {0, 1, -2}, - {2, 3, 5} - }); - - var expected = new[,] - { - {false, false, true}, - {true, true, false} - }.ToTensor(); - - var actual = TensorOperations.NotEquals(left, right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.Equal(leftConstructor.IsReversedStride, actual.IsReversedStride); - } - - [Theory] - [MemberData(nameof(GetDualTensorConstructors))] - public void MatrixMultiply(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {0, 1, 2}, - {3, 4, 5} - }); - - var right = rightConstructor.CreateFromArray( - new[,] - { - {0, 1, 2, 3, 4}, - {5, 6, 7, 8, 9}, - {10, 11, 12, 13, 14} - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - {0*0 + 1*5 + 2*10, 0*1 + 1*6 + 2*11, 0*2 + 1*7 + 2*12, 0*3 + 1*8 + 2*13, 0*4 + 1*9 + 2*14}, - {3*0 + 4*5 + 5*10, 3*1 + 4*6 + 5*11, 3*2 + 4*7 + 5*12, 3*3 + 4*8 + 5*13, 3*4 + 4*9 + 5*14} - }); - - var actual = left.MatrixMultiply(right); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - - [Theory] - [MemberData(nameof(GetDualTensorConstructors))] - public void Contract(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[, ,] - { - { - {0, 1}, - {2, 3} - }, - { - {4, 5}, - {6, 7} - }, - { - {8, 9}, - {10, 11} - } - }); - - var right = rightConstructor.CreateFromArray( - new[, ,] - { - { - {0, 1}, - {2, 3}, - {4, 5} - }, - { - {6, 7}, - {8, 9}, - {10, 11} - }, - { - {12, 13}, - {14, 15}, - {16, 17} - }, - { - {18, 19}, - {20, 21}, - {22, 23} - } - }); - - // contract a 3*2*2 with a 4*3*2 tensor, summing on (3*2)*2 and 4*(3*2) to produce a 2*4 tensor - var expected = leftConstructor.CreateFromArray( - new[,] - { - {110, 290, 470, 650}, - {125, 341, 557, 773}, - }); - var actual = TensorOperations.Contract(left, right, new[] { 0, 1 }, new[] { 1, 2 }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - // contract a 3*2*2 with a 4*3*2 tensor, summing on (3)*2*(2) and 4*(3*2) to produce a 2*4 tensor - expected = leftConstructor.CreateFromArray( - new[,] - { - {101, 263, 425, 587}, - {131, 365, 599, 833}, - }); - actual = TensorOperations.Contract(left, right, new[] { 0, 2 }, new[] { 1, 2 }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - - [Theory] - [MemberData(nameof(GetDualTensorConstructors))] - public void ContractWithSingleLengthDimension(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[,] - { - {1, 2, 3}, - {4, 5, 6}, - }); - - var right = rightConstructor.CreateFromArray( - new[,] - { - { 1, 2 }, - { 3, 4 }, - { 5, 6 } - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - { 22, 28 }, - { 49, 64 } - }); - - // contract a 2*3 with a 3*2 tensor, summing on 2*(3) and (3)*2 to produce a 2*2 tensor - var actual = TensorOperations.Contract(left, right, new[] { 1 }, new[] { 0 }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - - // contract a 1*2*3*1 with a 3*2 tensor, summing on 1*2*(3)*1 and (3)*2 to produce a 1*2*1*2 tensor - var reshapedLeft = left.Reshape(new int[] { 1, 2, 3, 1 }); - var reshapedExpected = expected.Reshape(new int[] { 1, 2, 1, 2 }); - actual = TensorOperations.Contract(reshapedLeft, right, new[] { 2 }, new[] { 0 }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, reshapedExpected)); - - } - - [Theory] - [MemberData(nameof(GetDualTensorConstructors))] - public void ContractMismatchedDimensions(TensorConstructor leftConstructor, TensorConstructor rightConstructor) - { - var left = leftConstructor.CreateFromArray( - new[] { 0, 1, 2, 3 }); - - var right = rightConstructor.CreateFromArray( - new[,] - { - { 0 }, - { 1 }, - { 2 } - }); - - var expected = leftConstructor.CreateFromArray( - new[,] - { - {0,0,0}, - {0,1,2}, - {0,2,4}, - {0,3,6}, - }); - - Assert.Throws(() => TensorOperations.Contract(left, right, new int[] { }, new[] { 1 })); - - // reshape to include dimension of length 1. - var leftReshaped = left.Reshape(new[] { 1, (int)left.Length }); - - var actual = TensorOperations.Contract(leftReshaped, right, new[] { 0 }, new[] { 1 }); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void GetArrayString(TensorConstructor constructor) - { - var tensor = constructor.CreateFromArray( - new[, ,] - { - { - {0, 1}, - {2, 3}, - {4, 5} - }, - { - {6, 7}, - {8, 9}, - {10, 11} - }, - { - {12, 13}, - {14, 15}, - {16, 17} - }, - { - {18, 19}, - {20, 21}, - {22, 23} - } - }); - - var expected = -@"{ - { - {0,1}, - {2,3}, - {4,5} - }, - { - {6,7}, - {8,9}, - {10,11} - }, - { - {12,13}, - {14,15}, - {16,17} - }, - { - {18,19}, - {20,21}, - {22,23} - } -}"; - - Assert.Equal(expected, tensor.GetArrayString(), ignoreLineEndingDifferences: !LineEndingsHelper.IsNewLineConsistent); - - var expectedNoSpace = expected.Replace(LineEndingsHelper.CompiledNewline, "").Replace(" ", ""); - Assert.Equal(expectedNoSpace, tensor.GetArrayString(false)); - } - - [Theory] - [MemberData(nameof(GetTensorAndResultConstructor))] - public void ToOtherTensor(TensorConstructor sourceConstructor, TensorConstructor resultConstructor) - { - var array = new[, ,] - { - { - {0, 1, 0, 0 }, - {0, 0, 0, 9 }, - {2, 0, 5, 0 } - }, - { - {3, 0, 0, 6 }, - {0, 0, 0, 0 }, - {0, 0, 4, 0 } - }, - { - {0, 2, 0, 0 }, - {8, 0, 0, 0 }, - {0, 0, 12, 0 } - }, - { - {5, 5, 5, 0 }, - {0, 0, 0, 15 }, - {0, 0, 42, 0 } - }, - { - {1, 0, 0, 4 }, - {0, 2, 0, 0 }, - {0, 0, 3, 0 } - } - }; - - var source = sourceConstructor.CreateFromArray(array); - - Tensor expected = resultConstructor.CreateFromArray(array); - - Tensor actual; - - switch (resultConstructor.TensorType) - { - case TensorType.Dense: - actual = source.ToDenseTensor(); - break; - case TensorType.Sparse: - var actualSparse = source.ToSparseTensor(); - actual = actualSparse; - var expectedSparse = expected as SparseTensor; - Assert.Equal(expectedSparse.NonZeroCount, actualSparse.NonZeroCount); - break; - case TensorType.CompressedSparse: - var actualCompressedSparse = source.ToCompressedSparseTensor(); - actual = actualCompressedSparse; - var expectedCompressedSparse = expected as CompressedSparseTensor; - Assert.Equal(expectedCompressedSparse.NonZeroCount, actualCompressedSparse.NonZeroCount); - if (sourceConstructor.TensorType != TensorType.Dense) - { - // expect packed values when going from sparse -> sparse - Assert.Equal(actualCompressedSparse.NonZeroCount, actualCompressedSparse.Values.Length); - } - break; - default: - throw new ArgumentException(nameof(resultConstructor.TensorType)); - } - - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, expected)); - Assert.True(StructuralComparisons.StructuralEqualityComparer.Equals(actual, source)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void TestICollectionMembers(TensorConstructor constructor) - { - var arr = new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 } - }; - - var tensor = constructor.CreateFromArray(arr); - ICollection tensorCollection = tensor; - - Assert.Equal(6, tensorCollection.Count); - - Assert.False(tensorCollection.IsSynchronized); - - Assert.True(ReferenceEquals(tensorCollection, tensorCollection.SyncRoot)); - - var actual = Array.CreateInstance(typeof(int), tensor.Length); - tensorCollection.CopyTo(actual, 0); - var expected = constructor.IsReversedStride ? - new[] { 1, 4, 2, 5, 3, 6 } : - new[] { 1, 2, 3, 4, 5, 6 }; - Assert.Equal(expected, actual); - - actual = Array.CreateInstance(typeof(int), tensor.Length + 2); - tensorCollection.CopyTo(actual, 2); - expected = constructor.IsReversedStride ? - new[] { 0, 0, 1, 4, 2, 5, 3, 6 } : - new[] { 0, 0, 1, 2, 3, 4, 5, 6 }; - Assert.Equal(expected, actual); - - Assert.Throws(() => tensorCollection.CopyTo(null, 0)); - Assert.Throws(() => tensorCollection.CopyTo(new int[3, 4], 0)); - Assert.Throws(() => tensorCollection.CopyTo(new int[5], 0)); - Assert.Throws(() => tensorCollection.CopyTo(new int[6], 1)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void TestIListMembers(TensorConstructor constructor) - { - var arr = new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 } - }; - - var tensor = constructor.CreateFromArray(arr); - IList tensorList = tensor; - - int expectedIndexValue = constructor.IsReversedStride ? 4 : 2; - Assert.Equal(expectedIndexValue, tensorList[1]); - - tensorList[1] = 7; - Assert.Equal(7, tensorList[1]); - var expected = constructor.IsReversedStride ? - new[] { 1, 7, 2, 5, 3, 6 } : - new[] { 1, 7, 3, 4, 5, 6 }; - Assert.Equal(expected, tensor); - - Assert.True(tensorList.IsFixedSize); - Assert.False(tensorList.IsReadOnly); - - Assert.Throws(() => (tensorList).Add(8)); - - Assert.True(tensorList.Contains(5)); - Assert.True(tensorList.Contains(6)); - Assert.False(tensorList.Contains(0)); - Assert.False(tensorList.Contains(42)); - Assert.False(tensorList.Contains("foo")); - - Assert.Equal(constructor.IsReversedStride ? 3 : 4, tensorList.IndexOf(5)); - Assert.Equal(5, tensorList.IndexOf(6)); - Assert.Equal(-1, tensorList.IndexOf(0)); - Assert.Equal(-1, tensorList.IndexOf(42)); - - Assert.Throws(() => (tensorList).Insert(2, 5)); - Assert.Throws(() => (tensorList).Remove(1)); - Assert.Throws(() => (tensorList).RemoveAt(0)); - - tensorList.Clear(); - Assert.Equal(new[] { 0, 0, 0, 0, 0, 0 }, tensor); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void TestICollectionTMembers(TensorConstructor constructor) - { - var arr = new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 } - }; - - var tensor = constructor.CreateFromArray(arr); - ICollection tensorCollection = tensor; - - Assert.Equal(6, tensorCollection.Count); - Assert.False(tensorCollection.IsReadOnly); - - Assert.Throws(() => tensorCollection.Add(8)); - Assert.Throws(() => tensorCollection.Remove(1)); - - Assert.True(tensorCollection.Contains(5)); - Assert.True(tensorCollection.Contains(6)); - Assert.False(tensorCollection.Contains(0)); - Assert.False(tensorCollection.Contains(42)); - - var actual = new int[tensor.Length]; - tensorCollection.CopyTo(actual, 0); - var expected = constructor.IsReversedStride ? - new[] { 1, 4, 2, 5, 3, 6 } : - new[] { 1, 2, 3, 4, 5, 6 }; - Assert.Equal(expected, actual); - - actual = new int[tensor.Length + 2]; - tensorCollection.CopyTo(actual, 2); - expected = constructor.IsReversedStride ? - new[] { 0, 0, 1, 4, 2, 5, 3, 6 } : - new[] { 0, 0, 1, 2, 3, 4, 5, 6 }; - Assert.Equal(expected, actual); - - Assert.Throws(() => tensorCollection.CopyTo(null, 0)); - Assert.Throws(() => tensorCollection.CopyTo(new int[5], 0)); - Assert.Throws(() => tensorCollection.CopyTo(new int[6], 1)); - - tensorCollection.Clear(); - Assert.Equal(new[] { 0, 0, 0, 0, 0, 0 }, tensor); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void TestIListTMembers(TensorConstructor constructor) - { - var arr = new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 } - }; - - var tensor = constructor.CreateFromArray(arr); - IList tensorList = tensor; - - int expectedIndexValue = constructor.IsReversedStride ? 4 : 2; - Assert.Equal(expectedIndexValue, tensorList[1]); - - tensorList[1] = 7; - Assert.Equal(7, tensorList[1]); - var expected = constructor.IsReversedStride ? - new[] { 1, 7, 2, 5, 3, 6 } : - new[] { 1, 7, 3, 4, 5, 6 }; - Assert.Equal(expected, tensor); - - Assert.Equal(constructor.IsReversedStride ? 3 : 4, tensorList.IndexOf(5)); - Assert.Equal(5, tensorList.IndexOf(6)); - Assert.Equal(-1, tensorList.IndexOf(0)); - Assert.Equal(-1, tensorList.IndexOf(42)); - - Assert.Throws(() => (tensorList).Insert(2, 5)); - Assert.Throws(() => (tensorList).RemoveAt(0)); - } - - [Theory] - [MemberData(nameof(GetSingleTensorConstructors))] - public void TestIReadOnlyTMembers(TensorConstructor constructor) - { - var arr = new[,] - { - { 1, 2, 3 }, - { 4, 5, 6 } - }; - - var tensor = constructor.CreateFromArray(arr); - - IReadOnlyCollection tensorCollection = tensor; - Assert.Equal(6, tensorCollection.Count); - - IReadOnlyList tensorList = tensor; - int expectedIndexValue = constructor.IsReversedStride ? 4 : 2; - Assert.Equal(expectedIndexValue, tensorList[1]); - } - - [Theory] - [MemberData(nameof(GetConstructedTensors))] - public void TestGetEnumerator(Tensor tensor) - { - static IEnumerable GetExpected(Tensor tensor) - { - for (int index = 0; index < tensor.Length; ++index) - yield return tensor.GetValue(index); - } - - Assert.Equal(GetExpected(tensor), tensor); - } - - [Theory] - [MemberData(nameof(GetConstructedTensors))] - public void TestEnumeratorReset(Tensor tensor) - { - static long AdvanceEnumerator(ref Tensor.Enumerator enumerator, long maxCount) - { - long count = 0; - while (count < maxCount && enumerator.MoveNext()) - count++; - - return count; - } - - static void TestStepCountIfInRange(Tensor tensor, long stepCount) - { - if (stepCount < 0 || stepCount > tensor.Length) - return; - - var enumerator = tensor.GetEnumerator(); - long actualStepCount = AdvanceEnumerator(ref enumerator, stepCount); - - Assert.Equal(stepCount, actualStepCount); - - enumerator.Reset(); - - var itemsPostReset = new List(); - while (enumerator.MoveNext()) - itemsPostReset.Add(enumerator.Current); - - Assert.Equal(tensor, itemsPostReset); - } - - TestStepCountIfInRange(tensor, 1); - TestStepCountIfInRange(tensor, tensor.Length - 1); - TestStepCountIfInRange(tensor, tensor.Length / 4); - TestStepCountIfInRange(tensor, tensor.Length - tensor.Length / 4); - TestStepCountIfInRange(tensor, tensor.Length / 2); - TestStepCountIfInRange(tensor, tensor.Length); - } - - [Theory] - [MemberData(nameof(GetConstructedTensors))] - public void TestEnumeratorDispose_DoesNotThrow(Tensor tensor) - { - var enumerator = tensor.GetEnumerator(); - - enumerator.Dispose(); - enumerator.Dispose(); - } - } -} diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorTestsBase.cs b/src/libraries/System.Numerics.Tensors/tests/TensorTestsBase.cs deleted file mode 100644 index 9774dd22662e6a..00000000000000 --- a/src/libraries/System.Numerics.Tensors/tests/TensorTestsBase.cs +++ /dev/null @@ -1,187 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Linq; - -namespace System.Numerics.Tensors.Tests -{ - public class TensorTestsBase - { - public enum TensorType - { - Dense, - Sparse, - CompressedSparse - }; - - public class TensorConstructor - { - public TensorType TensorType { get; set; } - - public bool IsReversedStride { get; set; } - - public Tensor CreateFromArray(Array array) - { - switch (TensorType) - { - case TensorType.Dense: - return array.ToTensor(IsReversedStride); - case TensorType.Sparse: - return array.ToSparseTensor(IsReversedStride); - case TensorType.CompressedSparse: - return array.ToCompressedSparseTensor(IsReversedStride); - } - - throw new ArgumentException(nameof(TensorType)); - } - public Tensor CreateFromDimensions(ReadOnlySpan dimensions) - { - switch (TensorType) - { - case TensorType.Dense: - return new DenseTensor(dimensions, IsReversedStride); - case TensorType.Sparse: - return new SparseTensor(dimensions, IsReversedStride); - case TensorType.CompressedSparse: - return new CompressedSparseTensor(dimensions, IsReversedStride); - } - - throw new ArgumentException(nameof(TensorType)); - } - - public override string ToString() - { - return $"{TensorType}, {nameof(IsReversedStride)} = {IsReversedStride}"; - } - } - - private static TensorType[] s_tensorTypes = new[] - { - TensorType.Dense, - TensorType.Sparse, - TensorType.CompressedSparse - }; - - private static bool[] s_reverseStrideValues = new[] - { - false, - true - }; - - public static IEnumerable GetSingleTensorConstructors() - { - foreach (TensorType tensorType in s_tensorTypes) - { - foreach (bool isReversedStride in s_reverseStrideValues) - { - yield return new[] - { - new TensorConstructor() - { - TensorType = tensorType, - IsReversedStride = isReversedStride - } - }; - } - } - } - - public static IEnumerable GetDualTensorConstructors() - { - foreach (TensorType leftTensorType in s_tensorTypes) - { - foreach (TensorType rightTensorType in s_tensorTypes) - { - foreach (bool isLeftReversedStride in s_reverseStrideValues) - { - foreach (bool isRightReversedStride in s_reverseStrideValues) - { - yield return new[] - { - new TensorConstructor() - { - TensorType = leftTensorType, - IsReversedStride = isLeftReversedStride - }, - new TensorConstructor() - { - TensorType = rightTensorType, - IsReversedStride = isRightReversedStride - } - }; - } - } - } - } - } - - public static IEnumerable GetTensorAndResultConstructor() - { - foreach (TensorType leftTensorType in s_tensorTypes) - { - foreach (TensorType rightTensorType in s_tensorTypes) - { - foreach (bool isReversedStride in s_reverseStrideValues) - { - yield return new[] - { - new TensorConstructor() - { - TensorType = leftTensorType, - IsReversedStride = isReversedStride - }, - new TensorConstructor() - { - TensorType = rightTensorType, - IsReversedStride = isReversedStride - } - }; - } - } - } - } - - public static IEnumerable GetConstructedTensors() - { - foreach (var ctor in GetSingleTensorConstructors().Select(x => (TensorConstructor)x[0])) - { - yield return new object[] { ctor.CreateFromArray(Array.Empty()) }; - yield return new object[] { ctor.CreateFromArray(new[] { 7 }) }; - yield return new object[] { ctor.CreateFromArray(new[] { 7, 14 }) }; - yield return new object[] { ctor.CreateFromArray(new[] { 7, 14, 21 }) }; - yield return new object[] - { - ctor.CreateFromArray(new[,] - { - { 3, 6, 9 }, - { 5, 10, 15 }, - { 7, 14, 21 }, - { 11, 22, 33 } - }) - }; - } - } - - public static NativeMemory NativeMemoryFromArray(T[] array) - { - return NativeMemoryFromArray((Array)array); - } - - public static NativeMemory NativeMemoryFromArray(Array array) - { - // this silly method takes a managed array and copies it over to unmanaged memory, - // **only for test purposes** - - var memory = NativeMemory.Allocate(array.Length); - var span = memory.GetSpan(); - int index = 0; - foreach (T item in array) - { - span[index++] = item; - } - - return memory; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 7d20cc72202dd1..266e49fc39dd94 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1033,7 +1033,7 @@ public static double Min(double val1, double val2) // // It propagates NaN inputs back to the caller and // otherwise returns the lesser of the inputs. It - // treats +0 as lesser than -0 as per the specification. + // treats +0 as greater than -0 as per the specification. if (val1 != val2) { @@ -1091,7 +1091,7 @@ public static float Min(float val1, float val2) // // It propagates NaN inputs back to the caller and // otherwise returns the lesser of the inputs. It - // treats +0 as lesser than -0 as per the specification. + // treats +0 as greater than -0 as per the specification. if (val1 != val2) { @@ -1145,7 +1145,7 @@ public static double MinMagnitude(double x, double y) // // It propagates NaN inputs back to the caller and // otherwise returns the input with a lesser magnitude. - // It treats +0 as lesser than -0 as per the specification. + // It treats +0 as greater than -0 as per the specification. double ax = Abs(x); double ay = Abs(y); diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index 2726d14492f6ab..de0efc14f0ac4f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -285,7 +285,7 @@ public static float MinMagnitude(float x, float y) // // It propagates NaN inputs back to the caller and // otherwise returns the input with a lesser magnitude. - // It treats +0 as lesser than -0 as per the specification. + // It treats +0 as greater than -0 as per the specification. float ax = Abs(x); float ay = Abs(y); From a4459b5da3ebe2fc4b615a26cfe6e795a1b706c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 21:38:03 -0700 Subject: [PATCH 272/345] [release/8.0] Fix: Config binder generator doesn't generate code when named arguments are out of order (#92257) * Fix Named parameters bug * Test the generator only, don't compare generated file row by row * Add other named parameter combinatios for other overloads in the test, add test for OptionsBuilder... and ServiceCollection extensins * Adjust line numbers with source generator updates * Move similar code section into helper method, don't exact exact line count * Apply feedbacks --------- Co-authored-by: Buyaa Namnan --- .../gen/Parser/ConfigurationBinder.cs | 19 +++- .../ConfigurationBinderTests.Generator.cs | 2 +- .../GeneratorTests.Baselines.Options.cs | 75 +++++++++++++ .../GeneratorTests.Baselines.cs | 106 ++++++++++++++++++ .../GeneratorTests.Helpers.cs | 8 ++ .../ConfigurationExtensionsTest.Generator.cs | 17 +++ 6 files changed, 223 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs index 9feafd72ce7c59..3996142adf9089 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs @@ -77,7 +77,7 @@ private void ParseBindInvocation_ConfigurationBinder(BinderInvocation invocation _ => throw new InvalidOperationException() }; - IArgumentOperation instanceArg = operation.Arguments[instanceIndex]; + IArgumentOperation instanceArg = GetArgumentForParameterAtIndex(operation.Arguments, instanceIndex); if (instanceArg.Parameter.Type.SpecialType != SpecialType.System_Object) { return; @@ -119,6 +119,19 @@ private void ParseBindInvocation_ConfigurationBinder(BinderInvocation invocation }; } + private static IArgumentOperation GetArgumentForParameterAtIndex(ImmutableArray arguments, int parameterIndex) + { + foreach (var argument in arguments) + { + if (argument.Parameter?.Ordinal == parameterIndex) + { + return argument; + } + } + + throw new InvalidOperationException(); + } + private void ParseGetInvocation(BinderInvocation invocation) { IInvocationOperation operation = invocation.Operation!; @@ -158,7 +171,7 @@ private void ParseGetInvocation(BinderInvocation invocation) } else { - ITypeOfOperation? typeOfOperation = operation.Arguments[1].ChildOperations.FirstOrDefault() as ITypeOfOperation; + ITypeOfOperation? typeOfOperation = GetArgumentForParameterAtIndex(operation.Arguments, 1).ChildOperations.FirstOrDefault() as ITypeOfOperation; type = typeOfOperation?.TypeOperand; if (paramCount is 2) @@ -218,7 +231,7 @@ private void ParseGetValueInvocation(BinderInvocation invocation) return; } - ITypeOfOperation? typeOfOperation = operation.Arguments[1].ChildOperations.FirstOrDefault() as ITypeOfOperation; + ITypeOfOperation? typeOfOperation = GetArgumentForParameterAtIndex(operation.Arguments, 1).ChildOperations.FirstOrDefault() as ITypeOfOperation; type = typeOfOperation?.TypeOperand; if (paramCount is 3) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs index 1ffb263c836a1c..5b6d824e87dbe9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigurationBinderTests.Generator.cs @@ -317,7 +317,7 @@ internal class ClassWithThisIdentifier /// /// These are regression tests for https://github.com/dotnet/runtime/issues/90909. /// Ensure that we don't emit root interceptors to handle types/members that - /// are inaccessible to the generated helpers. Tests for inaccessbile transitive members + /// are inaccessible to the generated helpers. Tests for inaccessible transitive members /// are covered in the shared (reflection/src-gen) , /// e.g. . /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index c3d1ce89c1206f..4480ab4066882c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -60,6 +60,81 @@ public async Task Configure_T_BinderOptions() => public async Task Configure_T_name_BinderOptions() => await VerifyAgainstBaselineUsingFile("Configure_T_name_BinderOptions.generated.txt", GetConfigureSource(@""""", section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + [Theory] + [InlineData("OptionsConfigurationServiceCollectionExtensions.Configure(config: section, services: services);")] + [InlineData("""OptionsConfigurationServiceCollectionExtensions.Configure(name: "", config: section, services: services);""")] + [InlineData("OptionsConfigurationServiceCollectionExtensions.Configure(configureBinder: _ => { }, config: section, services: services);")] + [InlineData("""OptionsConfigurationServiceCollectionExtensions.Configure(configureBinder: _ => { }, config: section, name: "", services: services);""")] + [InlineData("""OptionsConfigurationServiceCollectionExtensions.Configure(name: "", services: services, configureBinder: _ => { }, config: section);""")] + public async Task Configure_T_NamedParameters_OutOfOrder(string row) + { + string source = $$""" + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfiguration config = configurationBuilder.Build(); + IConfigurationSection section = config.GetSection("MySection"); + ServiceCollection services = new(); + + {{row}} + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + } + } + """; + + await VerifyThatSourceIsGenerated(source); + } + + [Theory] + [InlineData("OptionsBuilderConfigurationExtensions.Bind(config: config, optionsBuilder: optionsBuilder);")] + [InlineData("OptionsBuilderConfigurationExtensions.Bind(configureBinder: _ => { }, config: config, optionsBuilder: optionsBuilder);")] + [InlineData("OptionsBuilderConfigurationExtensions.Bind(config: config, configureBinder: _ => { }, optionsBuilder: optionsBuilder);")] + public async Task Bind_T_NamedParameters_OutOfOrder(string row) + { + string source = $$""" + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfiguration config = configurationBuilder.Build(); + var services = new ServiceCollection(); + OptionsBuilder optionsBuilder = new(services, ""); + + {{row}} + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + } + } + """; + + await VerifyThatSourceIsGenerated(source); + } + private string GetBindSource(string? configureActions = null) => $$""" using System.Collections.Generic; using Microsoft.Extensions.Configuration; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index c48148c74c5891..3c46f5f99818b1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -15,6 +15,112 @@ public partial class ConfigurationBindingGeneratorTests public async Task Bind() => await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, extType: ExtensionClassType.ConfigurationBinder); + [Theory] + [InlineData("ConfigurationBinder.Bind(instance: configObj, configuration: config);")] + [InlineData("""ConfigurationBinder.Bind(key: "", instance: configObj, configuration: config);""")] + [InlineData("""ConfigurationBinder.Bind(instance: configObj, key: "", configuration: config);""")] + [InlineData("ConfigurationBinder.Bind(configureOptions: _ => { }, configuration: config, instance: configObj);")] + [InlineData("ConfigurationBinder.Bind(configuration: config, configureOptions: _ => { }, instance: configObj);")] + public async Task Bind_NamedParameters_OutOfOrder(string row) + { + string source = $$""" + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + {{row}} + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + } + } + """; + + await VerifyThatSourceIsGenerated(source); + } + + [Theory] + [InlineData("var obj = ConfigurationBinder.Get(type: typeof(MyClass), configuration: config);")] + [InlineData("var obj = ConfigurationBinder.Get(configureOptions: _ => { }, configuration: config);")] + [InlineData("var obj = ConfigurationBinder.Get(configureOptions: _ => { }, type: typeof(MyClass), configuration: config);")] + [InlineData("var obj = ConfigurationBinder.Get(type: typeof(MyClass), configureOptions: _ => { }, configuration: config);")] + public async Task Get_TypeOf_NamedParametersOutOfOrder(string row) + { + string source = $$""" + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + {{row}} + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + } + } + """; + + await VerifyThatSourceIsGenerated(source); + } + + [Theory] + [InlineData("""var str = ConfigurationBinder.GetValue(key: "key", configuration: config, type: typeof(string));""")] + [InlineData("""var str = ConfigurationBinder.GetValue(key: "key", configuration: config);""")] + [InlineData("""var str = ConfigurationBinder.GetValue(key: "key", defaultValue: "default", configuration: config);""")] + [InlineData("""var str = ConfigurationBinder.GetValue(configuration: config, key: "key", defaultValue: "default");""")] + [InlineData("""var str = ConfigurationBinder.GetValue(defaultValue: "default", key: "key", configuration: config, type: typeof(string));""")] + [InlineData("""var str = ConfigurationBinder.GetValue(defaultValue: "default", type: typeof(string), key: "key", configuration: config);""")] + public async Task GetValue_NamedParametersOutOfOrder(string row) + { + string source = $$""" + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + {{row}} + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + } + } + """; + + await VerifyThatSourceIsGenerated(source); + } + [Fact] public async Task Bind_Instance() { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs index 0053cb41f37020..bee4d14072ad48 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -85,6 +85,14 @@ private enum ExtensionClassType ServiceCollection, } + private static async Task VerifyThatSourceIsGenerated(string testSourceCode) + { + var (d, r) = await RunGenerator(testSourceCode); + Assert.Equal(1, r.Length); + Assert.Empty(d); + Assert.True(r[0].SourceText.Lines.Count > 10); + } + private static async Task VerifyAgainstBaselineUsingFile( string filename, string testSourceCode, diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs index a18efc6909b71d..9b3aff8c495a77 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/ConfigurationExtensionsTest.Generator.cs @@ -156,5 +156,22 @@ public void TestBindingInvocationsWithNewlines_StaticCalls() ) ; } + + [Fact] + public void TestBindAndConfigureWithNamedParameters() + { + OptionsBuilder? optionsBuilder = CreateOptionsBuilder(); + IServiceCollection services = new ServiceCollection(); + + OptionsBuilderConfigurationExtensions.Bind(config: s_emptyConfig, optionsBuilder: optionsBuilder); + OptionsBuilderConfigurationExtensions.Bind(configureBinder: _ => { }, config: s_emptyConfig, optionsBuilder: optionsBuilder); + + OptionsBuilderConfigurationExtensions.BindConfiguration(configureBinder: _ => { }, configSectionPath: "path", optionsBuilder: optionsBuilder); + + OptionsConfigurationServiceCollectionExtensions.Configure(config: s_emptyConfig, services: services); + OptionsConfigurationServiceCollectionExtensions.Configure(name: "", config: s_emptyConfig, services: services); + OptionsConfigurationServiceCollectionExtensions.Configure(configureBinder: _ => { }, config: s_emptyConfig, services: services); + OptionsConfigurationServiceCollectionExtensions.Configure(name: "", configureBinder: _ => { }, config: s_emptyConfig, services: services); + } } } From f678a18f80574f3b9233406a76ffa93faf0fcbab Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Mon, 18 Sep 2023 21:38:23 -0700 Subject: [PATCH 273/345] Localized file check-in by OneLocBuild Task: Build definition ID 679: Build ID 2270458 (#92258) --- .../gen/Resources/xlf/Strings.cs.xlf | 2 +- .../gen/Resources/xlf/Strings.pt-BR.xlf | 2 +- .../gen/Resources/xlf/Strings.tr.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hans.xlf | 2 +- .../gen/Resources/xlf/Strings.zh-Hant.xlf | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf index 3f881b123eb971..8af274c8cb6562 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.cs.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Pro volání vazby se nevygenerovala logika vazby. Mezi nepodporované vstupní vzory patří obecná volání, předávání zabalených objektů a předávání typů, které nejsou public ani internal. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf index e15e781b7abfdc..965a1181aacd34 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.pt-BR.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + A lógica de associação não foi gerada para uma chamada de fichário. Padrões de entrada sem suporte incluem chamadas genéricas, passagem de objetos em caixa e passagem de tipos que não são 'públicos' ou 'internos'. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf index cd53389a70ed28..1ffbaa22a96a85 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.tr.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + Bağlama mantığı bir bağlayıcı çağrısı için oluşturulmadı. Desteklenmeyen giriş düzenleri şunları içerir: genel çağrılar, geçirilen kutulu nesneler ve ‘genel’ veya ‘iç’ olmayan geçirme türleri. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf index 55c321ec0d801f..dd89336534060a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + 没有为绑定器调用生成绑定逻辑。不支持的输入模式包括泛型调用、传递装箱对象和传递不是“public”或“internal”的类型。 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf index edc74d0c17ad97..a30c193b7f0115 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -9,7 +9,7 @@ Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. - Binding logic was not generated for a binder call. Unsupported input patterns include generic calls, passing boxed objects, and passing types that are not 'public' or 'internal'. + 未產生文件夾呼叫的繫結邏輯。不支援的輸入模式包括一般呼叫、傳遞方塊物件,以及非 'public' 或 'internal' 的傳遞類型。。 From c38ca786c62107935f48cdf156d3f23405efa85b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 21:38:55 -0700 Subject: [PATCH 274/345] [release/8.0] Use strategy in StrategyBasedComWrappers.ComputeVtables (#92250) * Use strategy in StrategyBasedComWrappers.ComputeVtables We didn't actually use the strategy object here, so users like WinForms can't actually use it. * Update src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/StrategyBasedComWrappers.cs Co-authored-by: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> --------- Co-authored-by: Jeremy Koritzinsky Co-authored-by: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> --- .../InteropServices/Marshalling/StrategyBasedComWrappers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/StrategyBasedComWrappers.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/StrategyBasedComWrappers.cs index 14ced03d3a7fd0..9741b482633c24 100644 --- a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/StrategyBasedComWrappers.cs +++ b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/StrategyBasedComWrappers.cs @@ -76,7 +76,7 @@ static IIUnknownInterfaceDetailsStrategy GetInteropStrategy() /// protected sealed override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) { - if (obj.GetType().GetCustomAttribute(typeof(ComExposedClassAttribute<>)) is IComExposedDetails details) + if (GetOrCreateInterfaceDetailsStrategy().GetComExposedTypeDetails(obj.GetType().TypeHandle) is { } details) { return details.GetComInterfaceEntries(out count); } From 18810713324b93a18fba99d3be2ac12bd2794cb0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 09:09:48 -0700 Subject: [PATCH 275/345] [release/8.0] Update dependencies from dotnet/roslyn (#92149) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies from https://github.com/dotnet/roslyn build 20230915.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23465.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230915.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23465.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230915.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23465.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230915.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23465.5 * Use InterceptorsPreviewNamespaces instead of the InterceptorsPreview feature * Update dependencies from https://github.com/dotnet/roslyn build 20230918.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23468.1 * Bring back removed lines * Add CSharpParseOption InterceptorsPreviewNamespaces feature to GeneratorTests.Helpers.cs * Add TODO comment to remove feature * Update dependencies from https://github.com/dotnet/roslyn build 20230918.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23468.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230918.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23462.10 -> To Version 4.8.0-3.23468.4 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- .../SourceGenerationTests/GeneratorTests.Helpers.cs | 5 ++++- ...onfiguration.Binder.SourceGeneration.Tests.csproj | 2 ++ ...Microsoft.Extensions.Logging.Configuration.csproj | 2 ++ .../src/Microsoft.Extensions.Logging.Console.csproj | 2 ++ ...igurationExtensions.SourceGeneration.Tests.csproj | 2 ++ 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 161eab1c82c64c..1cc807a9f61d92 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 1b7a6f807cb8ce709048debae6b771f4705a697a + a19fe34b7266ab7638a12c2b54748d89d35a21a7 - + https://github.com/dotnet/roslyn - 1b7a6f807cb8ce709048debae6b771f4705a697a + a19fe34b7266ab7638a12c2b54748d89d35a21a7 - + https://github.com/dotnet/roslyn - 1b7a6f807cb8ce709048debae6b771f4705a697a + a19fe34b7266ab7638a12c2b54748d89d35a21a7 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index f71e6cc183dd73..abad67dca392aa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23462.10 - 4.8.0-3.23462.10 - 4.8.0-3.23462.10 + 4.8.0-3.23468.4 + 4.8.0-3.23468.4 + 4.8.0-3.23468.4 SYSLIB1100,SYSLIB1101 $(Features);InterceptorsPreview + + $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration true diff --git a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj index c0074144e78d9f..820eb7fa062e72 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj @@ -4,6 +4,8 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true $(Features);InterceptorsPreview + + $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration true true Configuration support for Microsoft.Extensions.Logging. diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 0dceab438f82f3..1f12dab5b9ac44 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -8,6 +8,8 @@ true true $(Features);InterceptorsPreview + + $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration true true Console logger provider implementation for Microsoft.Extensions.Logging. diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj index f08d2bd649bc3f..2bdacc95ff39e6 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/tests/SourceGenerationTests/Microsoft.Extensions.Options.ConfigurationExtensions.SourceGeneration.Tests.csproj @@ -4,6 +4,8 @@ $(NetCoreAppCurrent);$(NetFrameworkMinimum) $(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER $(Features);InterceptorsPreview + + $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration true true From 575843df1aeb430a3071e2e494d29b59080751ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 09:15:33 -0700 Subject: [PATCH 276/345] [release/8.0] Fix downlevel build break in TensorPrimitives (#92270) * Fix downlevel build break in TensorPrimitives * Make net6.0 Tensors use ns2.0 implementation --------- Co-authored-by: Stephen Toub Co-authored-by: Eric StJohn --- .../ref/System.Numerics.Tensors.csproj | 2 +- .../src/System.Numerics.Tensors.csproj | 4 ++-- .../Tensors/TensorPrimitives.netcore.cs | 6 ++++++ .../Tensors/TensorPrimitives.netstandard.cs | 20 +++++++++---------- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj index 89bdef6ea38ed9..8d28b0e077d9cd 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj index 097fa244ad4913..be4a04702af5e1 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -16,11 +16,11 @@ - + - + diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs index 4f40aa31494c97..ae5af404ac1aff 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs @@ -1159,7 +1159,9 @@ public static float Invoke(Vector512 x) public static float Invoke(float x) => -x; public static Vector128 Invoke(Vector128 x) => -x; public static Vector256 Invoke(Vector256 x) => -x; +#if NET8_0_OR_GREATER public static Vector512 Invoke(Vector512 x) => -x; +#endif } private readonly struct AddMultiplyOperator : ITernaryOperator @@ -1167,7 +1169,9 @@ public static float Invoke(Vector512 x) public static float Invoke(float x, float y, float z) => (x + y) * z; public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) => (x + y) * z; public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) => (x + y) * z; +#if NET8_0_OR_GREATER public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) => (x + y) * z; +#endif } private readonly struct MultiplyAddOperator : ITernaryOperator @@ -1175,7 +1179,9 @@ public static float Invoke(Vector512 x) public static float Invoke(float x, float y, float z) => (x * y) + z; public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 z) => (x * y) + z; public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 z) => (x * y) + z; +#if NET8_0_OR_GREATER public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 z) => (x * y) + z; +#endif } private readonly struct LoadIdentity : IUnaryOperator diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs index 134364708b8e5d..ba3fc69bab527f 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs @@ -69,8 +69,8 @@ private static float CosineSimilarityCore(ReadOnlySpan x, ReadOnlySpan( float identityValue, ReadOnlySpan x, TLoad load = default, TAggregate aggregate = default) - where TLoad : IUnaryOperator - where TAggregate : IBinaryOperator + where TLoad : struct, IUnaryOperator + where TAggregate : struct, IBinaryOperator { // Initialize the result to the identity value float result = identityValue; @@ -112,8 +112,8 @@ private static float Aggregate( private static float Aggregate( float identityValue, ReadOnlySpan x, ReadOnlySpan y, TBinary binary = default, TAggregate aggregate = default) - where TBinary : IBinaryOperator - where TAggregate : IBinaryOperator + where TBinary : struct, IBinaryOperator + where TAggregate : struct, IBinaryOperator { // Initialize the result to the identity value float result = identityValue; @@ -156,7 +156,7 @@ private static float Aggregate( private static void InvokeSpanIntoSpan( ReadOnlySpan x, Span destination, TUnaryOperator op = default) - where TUnaryOperator : IUnaryOperator + where TUnaryOperator : struct, IUnaryOperator { if (x.Length > destination.Length) { @@ -203,7 +203,7 @@ private static void InvokeSpanIntoSpan( private static void InvokeSpanSpanIntoSpan( ReadOnlySpan x, ReadOnlySpan y, Span destination, TBinaryOperator op = default) - where TBinaryOperator : IBinaryOperator + where TBinaryOperator : struct, IBinaryOperator { if (x.Length != y.Length) { @@ -258,7 +258,7 @@ private static void InvokeSpanSpanIntoSpan( private static void InvokeSpanScalarIntoSpan( ReadOnlySpan x, float y, Span destination, TBinaryOperator op = default) - where TBinaryOperator : IBinaryOperator + where TBinaryOperator : struct, IBinaryOperator { if (x.Length > destination.Length) { @@ -309,7 +309,7 @@ private static void InvokeSpanScalarIntoSpan( private static void InvokeSpanSpanSpanIntoSpan( ReadOnlySpan x, ReadOnlySpan y, ReadOnlySpan z, Span destination, TTernaryOperator op = default) - where TTernaryOperator : ITernaryOperator + where TTernaryOperator : struct, ITernaryOperator { if (x.Length != y.Length || x.Length != z.Length) { @@ -369,7 +369,7 @@ private static void InvokeSpanSpanSpanIntoSpan( private static void InvokeSpanSpanScalarIntoSpan( ReadOnlySpan x, ReadOnlySpan y, float z, Span destination, TTernaryOperator op = default) - where TTernaryOperator : ITernaryOperator + where TTernaryOperator : struct, ITernaryOperator { if (x.Length != y.Length) { @@ -430,7 +430,7 @@ private static void InvokeSpanSpanScalarIntoSpan( private static void InvokeSpanScalarSpanIntoSpan( ReadOnlySpan x, float y, ReadOnlySpan z, Span destination, TTernaryOperator op = default) - where TTernaryOperator : ITernaryOperator + where TTernaryOperator : struct, ITernaryOperator { if (x.Length != z.Length) { From 3108db27c369bdfec2eaf28329656652a6201eab Mon Sep 17 00:00:00 2001 From: Matt Thalman Date: Tue, 19 Sep 2023 14:00:12 -0500 Subject: [PATCH 277/345] Update Newtonsoft.Json from 13.0.1 to 13.0.3 (#92277) * Update Newtonsoft.Json from 13.0.1 to 13.0.3 * Update source-build-externals * Add prebuilt exclusion --- eng/SourceBuildPrebuiltBaseline.xml | 7 ++++++- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/eng/SourceBuildPrebuiltBaseline.xml b/eng/SourceBuildPrebuiltBaseline.xml index 46dd7457d764aa..458b2d756cba9a 100644 --- a/eng/SourceBuildPrebuiltBaseline.xml +++ b/eng/SourceBuildPrebuiltBaseline.xml @@ -16,7 +16,12 @@ - + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1cc807a9f61d92..648b4f19642f87 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -100,9 +100,9 @@ 3dd2c0ef203db8fe0e849557960b4cd009afbaac - + https://github.com/dotnet/source-build-externals - de4dda48d0cf31e13182bc24107b2246c61ed483 + e9d6489787a5ea5400a31dfa34aa6ad6b590de9b diff --git a/eng/Versions.props b/eng/Versions.props index abad67dca392aa..dff5222a155585 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -191,7 +191,7 @@ 3.12.0 4.1.0 6.0.0 - 13.0.1 + 13.0.3 1.0.2 2.0.4 4.18.4 From a49a52951a185779e017f49681abf12943b9e8e8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 12:22:09 -0700 Subject: [PATCH 278/345] Update dependencies from https://github.com/dotnet/roslyn build 20230919.1 (#92288) Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23468.4 -> To Version 4.8.0-3.23469.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 648b4f19642f87..83e0c865d5612a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - a19fe34b7266ab7638a12c2b54748d89d35a21a7 + 9233e36abc5e2ca263dbd4d1616f35623440a935 - + https://github.com/dotnet/roslyn - a19fe34b7266ab7638a12c2b54748d89d35a21a7 + 9233e36abc5e2ca263dbd4d1616f35623440a935 - + https://github.com/dotnet/roslyn - a19fe34b7266ab7638a12c2b54748d89d35a21a7 + 9233e36abc5e2ca263dbd4d1616f35623440a935 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index dff5222a155585..f053a60a286cb8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23468.4 - 4.8.0-3.23468.4 - 4.8.0-3.23468.4 + 4.8.0-3.23469.1 + 4.8.0-3.23469.1 + 4.8.0-3.23469.1 - 8.0.0-preview-20230828.1 + 8.0.0-preview-20230918.1 8.0.0-rc.1.23406.6 From d3da653d407bede37c51b3ed7ecac0498ae63e39 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 13:00:17 -0700 Subject: [PATCH 280/345] [release/8.0] Update dependencies from 7 repositories (#92143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update dependencies from https://github.com/dotnet/emsdk build 20230915.1 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.2.23463.1 -> To Version 8.0.0-rc.2.23465.1 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230916.2 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23464.2 -> To Version 3.11.0-beta1.23466.2 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230916.2 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23464.2 -> To Version 3.11.0-beta1.23466.2 * Update dependencies from https://github.com/dotnet/emsdk build 20230918.1 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.2.23463.1 -> To Version 8.0.0-rc.2.23468.1 * Update dependencies from https://github.com/dotnet/emsdk build 20230918.2 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.2.23463.1 -> To Version 8.0.0-rtm.23468.2 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230918.1 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23464.2 -> To Version 3.11.0-beta1.23468.1 * Update dependencies from https://github.com/dotnet/cecil build 20230918.2 Microsoft.DotNet.Cecil From Version 0.11.4-alpha.23461.1 -> To Version 0.11.4-alpha.23468.2 * Update dependencies from https://github.com/dotnet/roslyn-analyzers build 20230918.1 Microsoft.CodeAnalysis.Analyzers , Microsoft.CodeAnalysis.NetAnalyzers From Version 3.11.0-beta1.23464.2 -> To Version 3.11.0-beta1.23468.1 * Update dependencies from https://github.com/dotnet/msquic build 20230918.1 System.Net.MsQuic.Transport From Version 8.0.0-alpha.1.23412.1 -> To Version 8.0.0-alpha.1.23468.1 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20230918.2 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 8.0.0-alpha.0.23461.1 -> To Version 8.0.0-alpha.0.23468.2 * Update dependencies from https://github.com/dotnet/icu build 20230918.3 Microsoft.NETCore.Runtime.ICU.Transport From Version 8.0.0-rc.2.23454.2 -> To Version 8.0.0-rtm.23468.3 * Roll back icu and emsdk to rc2 builds * Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20230919.1 Microsoft.SourceBuild.Intermediate.source-build-reference-packages From Version 8.0.0-alpha.1.23463.1 -> To Version 8.0.0-alpha.1.23469.1 * Update dependencies from https://github.com/dotnet/emsdk build 20230919.3 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.2.23463.1 -> To Version 8.0.0-rtm.23469.3 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> Co-authored-by: Larry Ewing --- eng/Version.Details.xml | 28 ++++++++++++++-------------- eng/Versions.props | 14 +++++++------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 83e0c865d5612a..04567c6742f81f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,12 +1,12 @@ - + https://github.com/dotnet/icu - 0bd4ee514dc6abe5cc664282709e70d5e26bb11d + ac7697a28716e68e986d3db72cbc10324f8961fe - + https://github.com/dotnet/msquic - 72811ab66f2611ac9f652cbb020dba033fc37401 + bbb1252b31e3a194be3163982d972e4583c75476 https://github.com/dotnet/wcf @@ -85,19 +85,19 @@ 02fe27cd6a9b001c8feb7938e6ef4b3799745759b - + https://github.com/dotnet/cecil - a112f15aa032c029b7d9c77df3427111d93cf407 + 89be445dd4936157533ad96bafb95f701430653a - + https://github.com/dotnet/emsdk - 1999c8c8ab7473a7e1c5b7bdf5ba6d9a985a69cc + 50bf805c8b5ca52abd34fde390609d8a54640246 - + https://github.com/dotnet/source-build-reference-packages - 3dd2c0ef203db8fe0e849557960b4cd009afbaac + d825c6693d4e26f63aaa93c3c1d057faa098e347 @@ -371,13 +371,13 @@ https://github.com/dotnet/roslyn 9233e36abc5e2ca263dbd4d1616f35623440a935 - + https://github.com/dotnet/roslyn-analyzers - 7ec4e8924bcbc469e00aa2bda84251c3e90aa96e + 2c9a20b6706b8a9ad650b41bff30980cf5af67ed - + https://github.com/dotnet/roslyn-analyzers - 7ec4e8924bcbc469e00aa2bda84251c3e90aa96e + 2c9a20b6706b8a9ad650b41bff30980cf5af67ed https://github.com/dotnet/sdk diff --git a/eng/Versions.props b/eng/Versions.props index f18a9bdf8b010d..113383aab30cf2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,8 +34,8 @@ - 3.11.0-beta1.23464.2 - 8.0.0-preview.23464.2 + 3.11.0-beta1.23468.1 + 8.0.0-preview.23468.1 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23461.1 + 0.11.4-alpha.23468.2 8.0.0-rc.1.23406.6 - 8.0.0-rc.2.23454.2 + 8.0.0-rc.2.23468.2 2.2.2 - 8.0.0-alpha.1.23412.1 + 8.0.0-alpha.1.23468.1 16.0.5-alpha.1.23423.1 16.0.5-alpha.1.23423.1 @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.2.23463.1 + 8.0.0-rtm.23469.3 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From 36b7c0b8e28e78109594f74a4119ab0e1247bdd0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 17:12:11 -0700 Subject: [PATCH 281/345] Update dependencies from https://github.com/dotnet/emsdk build 20230919.1 (#92306) Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rtm.23469.3 -> To Version 8.0.0-rc.2.23469.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 04567c6742f81f..489044e0d17884 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,9 +90,9 @@ 89be445dd4936157533ad96bafb95f701430653a - + https://github.com/dotnet/emsdk - 50bf805c8b5ca52abd34fde390609d8a54640246 + ca3e8e40f417e421141638c66dd301395afee66d diff --git a/eng/Versions.props b/eng/Versions.props index 113383aab30cf2..d56eeab17ef17d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rtm.23469.3 + 8.0.0-rc.2.23469.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From dcdc5f5269c2cb44c92a8ddf7917eaa30a9ca248 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 23:11:15 -0700 Subject: [PATCH 282/345] Fix options Validation with objects have indexers (#92311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tarek Mahmoud Sayed Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- .../src/DataAnnotationValidateOptions.cs | 3 +- .../OptionsRuntimeTests.cs | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs index e8f4b606882cf9..5b734edf32738c 100644 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs @@ -95,7 +95,8 @@ private static bool TryValidateOptions(object options, string qualifiedName, Lis foreach (PropertyInfo propertyInfo in options.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) { - if (propertyInfo.GetMethod is null) + // Indexers are properties which take parameters. Ignore them. + if (propertyInfo.GetMethod is null || propertyInfo.GetMethod.GetParameters().Length > 0) { continue; } diff --git a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs index b644eea74120f7..6109bccd296463 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/OptionsRuntimeTests.cs @@ -177,6 +177,30 @@ public void TestValidationWithEnumeration() result2.Failures); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public void TestObjectsWithIndexerProperties() + { + DataAnnotationValidateOptions dataAnnotationValidateOptions1 = new("MyDictionaryOptions"); + MyDictionaryOptionsOptionsValidator sourceGenOptionsValidator1 = new(); + + var options1 = new MyDictionaryOptions(); + ValidateOptionsResult result1 = sourceGenOptionsValidator1.Validate("MyDictionaryOptions", options1); + ValidateOptionsResult result2 = dataAnnotationValidateOptions1.Validate("MyDictionaryOptions", options1); + + Assert.True(result1.Succeeded); + Assert.True(result2.Succeeded); + + DataAnnotationValidateOptions> dataAnnotationValidateOptions2 = new("MyListOptions"); + MyListOptionsOptionsValidator sourceGenOptionsValidator2 = new(); + + var options2 = new MyListOptions() { Prop = "test" }; + result1 = sourceGenOptionsValidator2.Validate("MyListOptions", options2); + result2 = dataAnnotationValidateOptions2.Validate("MyListOptions", options2); + + Assert.True(result1.Succeeded); + Assert.True(result2.Succeeded); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] public void TestValidationWithCyclicReferences() { @@ -302,6 +326,12 @@ public partial class MySourceGenOptionsValidator : IValidateOptions { } + public class MyDictionaryOptions : Dictionary { [Required] public string Prop { get; set; } = "test"; } + [OptionsValidator] public partial class MyDictionaryOptionsOptionsValidator : IValidateOptions { } + + public class MyListOptions : List { [Required] public T Prop { get; set; } = default; } + [OptionsValidator] public partial class MyListOptionsOptionsValidator : IValidateOptions> { } + #if NET8_0_OR_GREATER public class OptionsUsingNewAttributes { From f6489fe1d785747308433213b4558171c63eef30 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 23:12:03 -0700 Subject: [PATCH 283/345] JIT: add missing xarch RMW case (#92293) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handle the case where we're indirectly updating a local with a value that is not a constant. Fixes #92218. Co-authored-by: Andy Ayers Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- src/coreclr/jit/emitxarch.cpp | 7 ++++ .../JitBlue/Runtime_92218/Runtime_92218.cs | 40 +++++++++++++++++++ .../Runtime_92218/Runtime_92218.csproj | 8 ++++ 3 files changed, 55 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.csproj diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 980d40a47ac318..1c48d1c52f0bb2 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -5485,6 +5485,13 @@ void emitter::emitInsRMW(instruction ins, emitAttr attr, GenTreeStoreInd* storeI { assert(!src->isContained()); // there must be one non-contained src + if (addr->isContained() && addr->OperIs(GT_LCL_ADDR)) + { + GenTreeLclVarCommon* lclVar = addr->AsLclVarCommon(); + emitIns_S_R(ins, attr, src->GetRegNum(), lclVar->GetLclNum(), lclVar->GetLclOffs()); + return; + } + // ind, reg id = emitNewInstrAmd(attr, offset); emitHandleMemOp(storeInd, id, emitInsModeFormat(ins, IF_ARD_RRD), ins); diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.cs b/src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.cs new file mode 100644 index 00000000000000..9b4696e31fc16c --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using Xunit; + +public struct MutableStruct +{ + private long _internalValue; + + public long InternalValue + { + get => Volatile.Read(ref _internalValue); + private set => Volatile.Write(ref _internalValue, value); + } + + public void Add(long value) => AddInternal(value); + private void AddInternal(long value) => InternalValue += value; + public MutableStruct(long value) => InternalValue = value; +} + +public static class Runtime_92218 +{ + [Fact] + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static void Problem() + { + var test = new MutableStruct(420); + var from = new MutableStruct(42); + + var wrapper = -new TimeSpan(3); + + while (test.InternalValue >= from.InternalValue) + { + test.Add(wrapper.Ticks); + } + } +} \ No newline at end of file diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92218/Runtime_92218.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From 09429dc1204365c3c7de70233db5e7c4f13ce3b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 23:12:45 -0700 Subject: [PATCH 284/345] Don't generate AddMask as it requires more explicit consideration of semantics (#92308) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tanner Gooding Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com> --- src/coreclr/jit/morph.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 153f9b8bba8a82..3deada8eec085b 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -10807,8 +10807,6 @@ GenTree* Compiler::fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node) } #if defined(TARGET_XARCH) - case NI_AVX512F_Add: - case NI_AVX512BW_Add: case NI_AVX512F_And: case NI_AVX512DQ_And: case NI_AVX512F_AndNot: @@ -10850,13 +10848,6 @@ GenTree* Compiler::fgOptimizeHWIntrinsic(GenTreeHWIntrinsic* node) switch (intrinsicId) { - case NI_AVX512F_Add: - case NI_AVX512BW_Add: - { - maskIntrinsicId = NI_AVX512F_AddMask; - break; - } - case NI_AVX512F_And: case NI_AVX512DQ_And: { From eafb0d69da05c5cbe52bd7c6eca77e256c40d3f4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:10:18 -0700 Subject: [PATCH 285/345] [release/8.0-rc1] [release/8.0] Events for IL methods without IL headers (#92317) * Events for IL methods without IL headers Dynamically generated methods like UnsafeAccessor functions are marked as IL, but don't contain an IL header. The lack of header is an indication the IL must be generated at runtime. * Debugger check for no IL header * Update src/coreclr/debug/daccess/stack.cpp Co-authored-by: Tlakaelel Axayakatl Ceja * Review feedback * Remove redundent calls and another spot to check. * Move header include --------- Co-authored-by: Aaron R Robinson Co-authored-by: Tlakaelel Axayakatl Ceja --- src/coreclr/debug/daccess/stack.cpp | 9 +- src/coreclr/inc/eventtracebase.h | 6 +- src/coreclr/utilcode/stresslog.cpp | 2 +- src/coreclr/vm/eventtrace.cpp | 21 ++-- src/coreclr/vm/jitinterface.cpp | 2 +- src/coreclr/vm/method.hpp | 2 +- src/coreclr/vm/prestub.cpp | 116 ++++++++++---------- src/coreclr/vm/versionresilienthashcode.cpp | 8 +- 8 files changed, 90 insertions(+), 76 deletions(-) diff --git a/src/coreclr/debug/daccess/stack.cpp b/src/coreclr/debug/daccess/stack.cpp index 9402d529eb8ea3..6b9f1a491c291c 100644 --- a/src/coreclr/debug/daccess/stack.cpp +++ b/src/coreclr/debug/daccess/stack.cpp @@ -1253,14 +1253,19 @@ ClrDataFrame::GetLocalSig(MetaSig** sig, { // It turns out we cannot really get rid of this check. Dynamic methods // (including IL stubs) do not have their local sig's available after JIT time. - if (!m_methodDesc->IsIL()) + // IL methods with dynamically generated IL (for example, UnsafeAccessors) may + // not have an IL header. + COR_ILMETHOD* ilHeader = m_methodDesc->IsIL() + ? m_methodDesc->GetILHeader() + : NULL; + if (ilHeader == NULL) { *sig = NULL; *count = 0; return E_FAIL; } - COR_ILMETHOD_DECODER methodDecoder(m_methodDesc->GetILHeader()); + COR_ILMETHOD_DECODER methodDecoder(ilHeader); mdSignature localSig = methodDecoder.GetLocalVarSigTok() ? methodDecoder.GetLocalVarSigTok() : mdSignatureNil; if (localSig == mdSignatureNil) diff --git a/src/coreclr/inc/eventtracebase.h b/src/coreclr/inc/eventtracebase.h index 97c3135153038c..3648b1f3a72136 100644 --- a/src/coreclr/inc/eventtracebase.h +++ b/src/coreclr/inc/eventtracebase.h @@ -905,7 +905,7 @@ namespace ETW BOOL fSendRichDebugInfoEvent, BOOL fGetCodeIds); static VOID SendEventsForNgenMethods(Module *pModule, DWORD dwEventOptions); - static VOID SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL); + static VOID SendMethodJitStartEvent(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL); static VOID SendMethodILToNativeMapEvent(MethodDesc * pMethodDesc, DWORD dwEventOptions, PCODE pNativeCodeStartAddress, DWORD nativeCodeId, ReJITID ilCodeId); static VOID SendMethodRichDebugInfo(MethodDesc * pMethodDesc, PCODE pNativeCodeStartAddress, DWORD nativeCodeId, ReJITID ilCodeId, MethodDescSet* sentMethodDetailsSet); static VOID SendMethodEvent(MethodDesc *pMethodDesc, DWORD dwEventOptions, BOOL bIsJit, SString *namespaceOrClassName=NULL, SString *methodName=NULL, SString *methodSignature=NULL, PCODE pNativeCodeStartAddress = 0, PrepareCodeConfig *pConfig = NULL, MethodDescSet* sentMethodDetailsSet = NULL); @@ -938,7 +938,7 @@ namespace ETW static VOID GetR2RGetEntryPointStart(MethodDesc *pMethodDesc); static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint); - static VOID MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); + static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID SendMethodDetailsEvent(MethodDesc *pMethodDesc); static VOID SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, MethodDescSet* set); @@ -952,7 +952,7 @@ namespace ETW public: static VOID GetR2RGetEntryPointStart(MethodDesc *pMethodDesc) {}; static VOID GetR2RGetEntryPoint(MethodDesc *pMethodDesc, PCODE pEntryPoint) {}; - static VOID MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); + static VOID MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature); static VOID MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature, PCODE pNativeCodeStartAddress, PrepareCodeConfig *pConfig); static VOID StubInitialized(ULONGLONG ullHelperStartAddress, LPCWSTR pHelperName) {}; static VOID StubsInitialized(PVOID *pHelperStartAddress, PVOID *pHelperNames, LONG ulNoOfHelpers) {}; diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp index c55c5afe9249c8..90ad5900473ed7 100644 --- a/src/coreclr/utilcode/stresslog.cpp +++ b/src/coreclr/utilcode/stresslog.cpp @@ -12,9 +12,9 @@ #include "switches.h" #include "stresslog.h" #include "clrhost.h" +#include "ex.h" #define DONOT_DEFINE_ETW_CALLBACK #include "eventtracebase.h" -#include "ex.h" #if !defined(STRESS_LOG_READONLY) #ifdef HOST_WINDOWS diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index b9a82cfb7c28e9..9498f00edf4329 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -3555,7 +3555,7 @@ VOID ETW::MethodLog::MethodJitted(MethodDesc *pMethodDesc, SString *namespaceOrC /*************************************************/ /* This is called by the runtime when method jitting started */ /*************************************************/ -VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) +VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, COR_ILMETHOD_DECODER* methodDecoder, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) { CONTRACTL { NOTHROW; @@ -3570,7 +3570,7 @@ VOID ETW::MethodLog::MethodJitting(MethodDesc *pMethodDesc, SString *namespaceOr CLR_JIT_KEYWORD)) { pMethodDesc->GetMethodInfo(*namespaceOrClassName, *methodName, *methodSignature); - ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, namespaceOrClassName, methodName, methodSignature); + ETW::MethodLog::SendMethodJitStartEvent(pMethodDesc, methodDecoder, namespaceOrClassName, methodName, methodSignature); } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } @@ -4528,7 +4528,12 @@ VOID ETW::MethodLog::SendNonDuplicateMethodDetailsEvent(MethodDesc* pMethodDesc, /*****************************************************************/ /* This routine is used to send an ETW event just before a method starts jitting*/ /*****************************************************************/ -VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *namespaceOrClassName, SString *methodName, SString *methodSignature) +VOID ETW::MethodLog::SendMethodJitStartEvent( + MethodDesc *pMethodDesc, + COR_ILMETHOD_DECODER* methodDecoder, + SString *namespaceOrClassName, + SString *methodName, + SString *methodSignature) { CONTRACTL { THROWS; @@ -4566,15 +4571,13 @@ VOID ETW::MethodLog::SendMethodJitStartEvent(MethodDesc *pMethodDesc, SString *n ulMethodToken = (ULONG)0; } else - ulMethodToken = (ULONG)pMethodDesc->GetMemberDef(); - - if(pMethodDesc->IsIL()) { - COR_ILMETHOD_DECODER::DecoderStatus decoderstatus = COR_ILMETHOD_DECODER::FORMAT_ERROR; - COR_ILMETHOD_DECODER ILHeader(pMethodDesc->GetILHeader(), pMethodDesc->GetMDImport(), &decoderstatus); - ulMethodILSize = (ULONG)ILHeader.GetCodeSize(); + ulMethodToken = (ULONG)pMethodDesc->GetMemberDef(); } + if (methodDecoder != NULL) + ulMethodILSize = methodDecoder->GetCodeSize(); + SString tNamespace, tMethodName, tMethodSignature; if(!namespaceOrClassName|| !methodName|| !methodSignature || (methodName->IsEmpty() && namespaceOrClassName->IsEmpty() && methodSignature->IsEmpty())) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 1a3439bdd235ef..74ee2f7482e747 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -12286,7 +12286,7 @@ static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr, SString namespaceOrClassName, methodName, methodSignature; // Fire an ETW event to mark the beginning of JIT'ing - ETW::MethodLog::MethodJitting(reinterpret_cast(info->ftn), &namespaceOrClassName, &methodName, &methodSignature); + ETW::MethodLog::MethodJitting(reinterpret_cast(info->ftn), NULL, &namespaceOrClassName, &methodName, &methodSignature); CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 4b34045b57671e..e51d9f7453d35e 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1819,7 +1819,7 @@ class MethodDesc PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0); PCODE JitCompileCode(PrepareCodeConfig* pConfig); PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry); - PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode); + PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode); public: bool TryGenerateUnsafeAccessor(DynamicResolver** resolver, COR_ILMETHOD_DECODER** methodILDecoder); diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 174e48565f31b8..32944952301648 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -709,6 +709,53 @@ PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig) } } +namespace +{ + COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pDecoderMemory) + { + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL); + _ASSERTE(!pMD->IsNoMetadata()); + _ASSERTE(pConfig != NULL); + _ASSERTE(pDecoderMemory != NULL); + + COR_ILMETHOD_DECODER* pHeader = NULL; + COR_ILMETHOD* ilHeader = pConfig->GetILHeader(); + if (ilHeader == NULL) + return NULL; + + COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::FORMAT_ERROR; + { + // Decoder ctor can AV on a malformed method header + AVInRuntimeImplOkayHolder AVOkay; + pHeader = new (pDecoderMemory) COR_ILMETHOD_DECODER(ilHeader, pMD->GetMDImport(), &status); + } + + if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) + COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); + + return pHeader; + } + + COR_ILMETHOD_DECODER* GetAndVerifyILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory) + { + STANDARD_VM_CONTRACT; + _ASSERTE(pMD != NULL); + if (pMD->IsIL()) + { + return GetAndVerifyMetadataILHeader(pMD, pConfig, pIlDecoderMemory); + } + else if (pMD->IsILStub()) + { + ILStubResolver* pResolver = pMD->AsDynamicMethodDesc()->GetILStubResolver(); + return pResolver->GetILHeader(); + } + + _ASSERTE(pMD->IsNoMetadata()); + return NULL; + } +} + PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry) { STANDARD_VM_CONTRACT; @@ -759,11 +806,18 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J } #endif // PROFILING_SUPPORTED + // The profiler may have changed the code on the callback. Need to + // pick up the new code. + // + // (don't want this for OSR, need to see how it works) + COR_ILMETHOD_DECODER ilDecoderTemp; + COR_ILMETHOD_DECODER* pilHeader = GetAndVerifyILHeader(this, pConfig, &ilDecoderTemp); + if (!ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_JIT_KEYWORD)) { - pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode); + pCode = JitCompileCodeLocked(pConfig, pilHeader, pEntry, &sizeOfCode); } else { @@ -778,12 +832,13 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J // a small stub of native code but no native-IL mapping. #ifndef FEATURE_INTERPRETER ETW::MethodLog::MethodJitting(this, + pilHeader, &namespaceOrClassName, &methodName, &methodSignature); #endif - pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode); + pCode = JitCompileCodeLocked(pConfig, pilHeader, pEntry, &sizeOfCode); // Interpretted methods skip this notification #ifdef FEATURE_INTERPRETER @@ -869,66 +924,11 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J return pCode; } -namespace -{ - COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pDecoderMemory) - { - STANDARD_VM_CONTRACT; - _ASSERTE(pMD != NULL); - _ASSERTE(!pMD->IsNoMetadata()); - _ASSERTE(pConfig != NULL); - _ASSERTE(pDecoderMemory != NULL); - - COR_ILMETHOD_DECODER* pHeader = NULL; - COR_ILMETHOD* ilHeader = pConfig->GetILHeader(); - if (ilHeader == NULL) - return NULL; - - COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::FORMAT_ERROR; - { - // Decoder ctor can AV on a malformed method header - AVInRuntimeImplOkayHolder AVOkay; - pHeader = new (pDecoderMemory) COR_ILMETHOD_DECODER(ilHeader, pMD->GetMDImport(), &status); - } - - if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL); - - return pHeader; - } - - COR_ILMETHOD_DECODER* GetAndVerifyILHeader(MethodDesc* pMD, PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory) - { - STANDARD_VM_CONTRACT; - _ASSERTE(pMD != NULL); - if (pMD->IsIL()) - { - return GetAndVerifyMetadataILHeader(pMD, pConfig, pIlDecoderMemory); - } - else if (pMD->IsILStub()) - { - ILStubResolver* pResolver = pMD->AsDynamicMethodDesc()->GetILStubResolver(); - return pResolver->GetILHeader(); - } - - _ASSERTE(pMD->IsNoMetadata()); - return NULL; - } -} - -PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, ULONG* pSizeOfCode) +PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pilHeader, JitListLockEntry* pEntry, ULONG* pSizeOfCode) { STANDARD_VM_CONTRACT; PCODE pCode = NULL; - - // The profiler may have changed the code on the callback. Need to - // pick up the new code. - // - // (don't want this for OSR, need to see how it works) - COR_ILMETHOD_DECODER ilDecoderTemp; - COR_ILMETHOD_DECODER* pilHeader = GetAndVerifyILHeader(this, pConfig, &ilDecoderTemp); - CORJIT_FLAGS jitFlags; PCODE pOtherCode = NULL; diff --git a/src/coreclr/vm/versionresilienthashcode.cpp b/src/coreclr/vm/versionresilienthashcode.cpp index b3ba764baac595..85bd146d8dc463 100644 --- a/src/coreclr/vm/versionresilienthashcode.cpp +++ b/src/coreclr/vm/versionresilienthashcode.cpp @@ -286,7 +286,7 @@ bool AddVersionResilientHashCodeForInstruction(ILInstructionParser *parser, xxHa hash->Add(varValue); break; } - + case InlineVar: // 2 byte value which is token change resilient { uint16_t varValue; @@ -388,6 +388,12 @@ bool GetVersionResilientILCodeHashCode(MethodDesc *pMD, int* hashCode, unsigned* initLocals = (options & CORINFO_OPT_INIT_LOCALS) == CORINFO_OPT_INIT_LOCALS; } + else if (!pMD->HasILHeader()) + { + // Dynamically generated IL methods like UnsafeAccessors may not have + // an IL header. + return false; + } else { COR_ILMETHOD_DECODER header(pMD->GetILHeader(TRUE), pMD->GetMDImport(), NULL); From b0b595f388377c351ca980707424b2c66ed9ca2c Mon Sep 17 00:00:00 2001 From: Maoni Stephens Date: Wed, 20 Sep 2023 09:25:14 -0700 Subject: [PATCH 286/345] [release/8.0-rc2] porting DATAS change back to RC2 (#92323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * new synchronization mechanism for DATAS (#90726) The current mechanism has a fundamental flaw which is the idling threads can start running at unpredictable times when they are woken up. This causes all sorts of problems. For example, when a thread gets here in gc_thread_function - `if (n_heaps <= heap_number)` if it's true it's supposed to wait. But its execution could be delayed so after it reads n_heaps it can stop for a while since no thread is waiting on this thread anyway... till some time later when a heap count changes happens again and it requires this thread to participating. And now this thread does the comparison and discovers that it needs to wait so it goes idle and all other threads will just be waiting for this thread to join. Another example is it's not safe to change the heap count for a join from a larger one to a smaller one. It's fine to change from a smaller one to a larger one because all the threads participating will have to run in order for a join to finish. But if no one is waiting on a thread, it could just wake up from the event being set by the last thread joining and not run for a while. Then go back to the respin loop at a point where the color was changed and changed again! So now it thinks it can proceed with a join it does not belong to. And of course that wouldn't work. The way threads are going idle/waking up is hard to keep track of - not only does it involve the gc_start_event and gc_idle_thread_event, it also uses WaitForGCEvent which is used by SuspendEE/RestartEE which in turn means whenever we want to call these we'd need to care about how that would affect this. The new mechanism only uses gc_start_event and gc_idle_thread_event, but I changed gc_idle_thread_event to a per heap event. We can easily track which threads are going idling easily - whenever a thread is about to wait on the idle event, we increase the current idle_thread_count. And when we increase the heap count we only set the gc_idle_thread_event for the new heaps that are about to participate so we can deduct that many from idle_thread_count. There's a much simpler code path between "we know we don't need these threads anymore" to "these threads are at a known point" because the next time gc_start_event is set (ie, a GC is requested) we make sure to get these threads to a good known point, ie, we wait till all of them have completed increasing idle_thread_count. Also fixed a couple of other problems that I hit while testing the new mechanism - We are setting freeable_uoh_segment and freeable_soh_segment in decommission_heap to DECOMMISSIONED_REGION_P. And this causes us to simply lose the value for them. We should make sure we do push these to the free regions before we start changing the heap count. We should also call background_delay_delete_uoh_segments before we start changing the heap count so we can get rid of the regions marked with heap_segment_flags_uoh_delete. If we allow these to be rearranged in equalize_promoted_bytes it means the order can change the invariant of the first region never being deleted no longer holds true and we can AV in this method. I added an new method delay_free_segments to perform both tasks. The accounting of generation_free_list_space is slightly off for LOH which causes us to hit assert (gen_size >= dd_fragmentation (dd)); in change_heap_count because we were not counting the loh_pad size. I also disabled assert (free_list_space_decrease <= dd_fragmentation (dd)); for gen2 since I'm seeing this fired while I'm doing stress runs. I have yet to investigate this since I didn't want to add yet more changes to this PR. * fixed problems with how sampling is done and how we suspend to change heap count in DATAS (#91712) + Moved the sample recording into when we are suspended. The way we were calculating the throughput cost was in check_heap_count (which is called right after we restart EE on heap0), we record the msl_wait_time (and reset it to 0 for soh/uoh). This is not synchronized with the allocating threads (which are already running at this point). So what can happen is the allocating threads are already accumulated more wait time which is attributed to this GC but it's not within the period we are counting for this GC (and we lose this part for the next GC). For BGC this is incorrect. If an ephemeral GC did happen before the BGC starts, we'd be adding a sample for that GC which is basically correct for that eph GC. But if an eph GC did not happen, we are just adding a random sample which is calculating the tcp as (msl wait + whatever GC that was finished before this BGC) so obviously incorrect. + Added gen2 sampling - this was adapted from Peter's gen2 sampling changes. This serves as a backstop in case the existing sampling doesn't ever pick gen2 GC costs. I made the following fixes - 1) changed the way we calculated the median 2) moved where this is calculated to again avoid timing issues 3) made the gen2 samples actually count instead of losing that info if we happen to sample when a gen2 didn't just occur. + Changed when check_heap_count is called - the previous place is right after a suspension which does not help with spacing the suspension time out (it was "suspend for GC" then "immediately suspend to change heap count"). And it caused a problem with BGC which was it always tried to change heap count when it couldn't because BGC was in progress. I changed this to be on a timeout to intentionally space the suspensions out. Now most of the time, heap count changes happen due to this time out. If we are really in a situation where GCs are happening too quickly and we return from waiting on the ee_suspend_event due to a GC started, we change the heap count right before we do a GC. So this also helps with the BGC problem. * gen0_bricks_cleared flag needs to be propagated when we change heap count (#90457) when we change the heap count, in heap X we get a region from heap Y and the gen0_bricks_cleared flag from Y says false but heap X says true. So when we check the bricks on heap X, we assume it’s true but it’s not. the fix is to detect if any heap has this flag as false and if so make all heaps’ flag false (tracking which region is moved from which other heap is something we need additional recording for and it’s not really worth doing just for this) * a logging change --------- Co-authored-by: Maoni0 --- src/coreclr/gc/gc.cpp | 1001 +++++++++++++++++++++++++------------ src/coreclr/gc/gcconfig.h | 1 + src/coreclr/gc/gcpriv.h | 93 +++- 3 files changed, 746 insertions(+), 349 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index daeadfe9821b8c..7351954070725e 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -823,6 +823,11 @@ class t_join join_struct.r_join_lock = n_th; } + int get_num_threads() + { + return join_struct.n_threads; + } + void destroy () { dprintf (JOIN_LOG, ("Destroying join structure")); @@ -887,6 +892,8 @@ class t_join // avoid race due to the thread about to reset the event (occasionally) being preempted before ResetEvent() if (color == join_struct.lock_color.LoadWithoutBarrier()) { + dprintf (9999, ("---h%d %d j%d %d - respin!!! (c:%d-%d)", + gch->heap_number, join_id, join_struct.n_threads, color, join_struct.lock_color.LoadWithoutBarrier())); goto respin; } @@ -1117,6 +1124,25 @@ t_join bgc_t_join; } \ } +#define spin_and_wait(count_to_spin, expr) \ +{ \ + while (!expr) \ + { \ + for (int j = 0; j < count_to_spin; j++) \ + { \ + if (expr) \ + { \ + break; \ + } \ + YieldProcessor (); \ + } \ + if (!(expr)) \ + { \ + GCToOSInterface::YieldThread (0); \ + } \ + } \ +} + #ifdef BACKGROUND_GC #define max_pending_allocs 64 @@ -1429,8 +1455,6 @@ enter_msl_status gc_heap::enter_spin_lock_msl_helper (GCSpinLock* msl) { #ifdef DYNAMIC_HEAP_COUNT uint64_t start = GetHighPrecisionTimeStamp(); - - msl->msl_wait_count++; #endif //DYNAMIC_HEAP_COUNT unsigned int i = 0; @@ -1485,7 +1509,7 @@ enter_msl_status gc_heap::enter_spin_lock_msl_helper (GCSpinLock* msl) #ifdef DYNAMIC_HEAP_COUNT uint64_t end = GetHighPrecisionTimeStamp(); Interlocked::ExchangeAdd64 (&msl->msl_wait_time, end - start); - dprintf (6666, ("wait for msl lock total time: %zd, total count: %zd, this time: %zd, this count: %u", msl->msl_wait_time, msl->msl_wait_count, end - start, i)); + dprintf (3, ("h%d wait for msl lock wait time %zd, total wait time: %zd", heap_number, (end - start), msl->msl_wait_time)); #endif //DYNAMIC_HEAP_COUNT } while (Interlocked::CompareExchange (&msl->lock, lock_taken, lock_free) != lock_free); @@ -2318,9 +2342,6 @@ sorted_table* gc_heap::seg_table; #ifdef MULTIPLE_HEAPS GCEvent gc_heap::ee_suspend_event; -#ifdef DYNAMIC_HEAP_COUNT -GCEvent gc_heap::gc_idle_thread_event; -#endif //DYNAMIC_HEAP_COUNT size_t gc_heap::min_gen0_balance_delta = 0; size_t gc_heap::min_balance_threshold = 0; #endif //MULTIPLE_HEAPS @@ -2919,6 +2940,12 @@ BOOL gc_heap::should_expand_in_full_gc = FALSE; #ifdef DYNAMIC_HEAP_COUNT int gc_heap::dynamic_adaptation_mode = dynamic_adaptation_default; gc_heap::dynamic_heap_count_data_t SVR::gc_heap::dynamic_heap_count_data; +uint64_t gc_heap::last_suspended_end_time = 0; +size_t gc_heap::gc_index_full_gc_end = 0; + +#ifdef STRESS_DYNAMIC_HEAP_COUNT +int gc_heap::heaps_in_this_gc = 0; +#endif //STRESS_DYNAMIC_HEAP_COUNT #endif // DYNAMIC_HEAP_COUNT // Provisional mode related stuff. @@ -6967,12 +6994,6 @@ BOOL gc_heap::create_thread_support (int number_of_heaps) { goto cleanup; } -#ifdef DYNAMIC_HEAP_COUNT - if (!gc_idle_thread_event.CreateOSManualEventNoThrow (FALSE)) - { - goto cleanup; - } -#endif //DYNAMIC_HEAP_COUNT if (!ee_suspend_event.CreateOSAutoEventNoThrow (FALSE)) { goto cleanup; @@ -7020,10 +7041,6 @@ bool gc_heap::create_gc_thread () return GCToEEInterface::CreateThread(gc_thread_stub, this, false, ".NET Server GC"); } -#ifdef DYNAMIC_HEAP_COUNT -static size_t prev_change_heap_count_gc_index; -#endif //DYNAMIC_HEAP_COUNT - #ifdef _MSC_VER #pragma warning(disable:4715) //IA64 xcompiler recognizes that without the 'break;' the while(1) will never end and therefore not return a value for that code path #endif //_MSC_VER @@ -7042,18 +7059,87 @@ void gc_heap::gc_thread_function () if (heap_number == 0) { - uint32_t wait_result = gc_heap::ee_suspend_event.Wait(gradual_decommit_in_progress_p ? DECOMMIT_TIME_STEP_MILLISECONDS : INFINITE, FALSE); + bool wait_on_time_out_p = gradual_decommit_in_progress_p; + uint32_t wait_time = DECOMMIT_TIME_STEP_MILLISECONDS; +#ifdef DYNAMIC_HEAP_COUNT + // background_running_p can only change from false to true during suspension. + if (!gc_heap::background_running_p () && dynamic_heap_count_data.should_change_heap_count) + { + assert (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes); + + dynamic_heap_count_data_t::sample& sample = dynamic_heap_count_data.samples[dynamic_heap_count_data.sample_index]; + wait_time = min (wait_time, (uint32_t)(sample.elapsed_between_gcs / 1000 / 3)); + wait_time = max (wait_time, 1); + + dprintf (6666, ("gc#0 thread waiting for %d ms (betwen GCs %I64d)", wait_time, sample.elapsed_between_gcs)); + } +#endif //DYNAMIC_HEAP_COUNT + uint32_t wait_result = gc_heap::ee_suspend_event.Wait(wait_on_time_out_p ? wait_time : INFINITE, FALSE); + dprintf (9999, ("waiting for ee done res %d (timeout %d, %I64d ms since last suspend end)(should_change_heap_count is %d) (gradual_decommit_in_progress_p %d)", + wait_result, wait_time, ((GetHighPrecisionTimeStamp() - last_suspended_end_time) / 1000), + dynamic_heap_count_data.should_change_heap_count, gradual_decommit_in_progress_p)); if (wait_result == WAIT_TIMEOUT) { - decommit_lock.Enter(); - gradual_decommit_in_progress_p = decommit_step (DECOMMIT_TIME_STEP_MILLISECONDS); - decommit_lock.Leave(); +#ifdef DYNAMIC_HEAP_COUNT + if (dynamic_heap_count_data.should_change_heap_count) + { +#ifdef BACKGROUND_GC + if (!gc_heap::background_running_p ()) +#endif //BACKGROUND_GC + { + dprintf (6666, ("changing heap count due to timeout")); + check_heap_count(); + } + } +#endif //DYNAMIC_HEAP_COUNT + + if (gradual_decommit_in_progress_p) + { + decommit_lock.Enter (); + gradual_decommit_in_progress_p = decommit_step (DECOMMIT_TIME_STEP_MILLISECONDS); + decommit_lock.Leave (); + } continue; } +#ifdef DYNAMIC_HEAP_COUNT + // We might want to consider also doing this when a BGC finishes. + if (dynamic_heap_count_data.should_change_heap_count) + { +#ifdef BACKGROUND_GC + if (!gc_heap::background_running_p ()) +#endif //BACKGROUND_GC + { + // this was a request to do a GC so make sure we follow through with one. + dprintf (6666, ("changing heap count at a GC start")); + check_heap_count (); + } + } + + // wait till the threads that should have gone idle at least reached the place where they are about to wait on the idle event. + if ((gc_heap::dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) && + (n_heaps != dynamic_heap_count_data.last_n_heaps)) + { + int spin_count = 1024; + int idle_thread_count = n_max_heaps - n_heaps; + dprintf (9999, ("heap count changed %d->%d, idle should be %d and is %d", dynamic_heap_count_data.last_n_heaps, n_heaps, + idle_thread_count, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); + if (idle_thread_count != dynamic_heap_count_data.idle_thread_count) + { + spin_and_wait (spin_count, (idle_thread_count == dynamic_heap_count_data.idle_thread_count)); + dprintf (9999, ("heap count changed %d->%d, now idle is %d", dynamic_heap_count_data.last_n_heaps, n_heaps, + VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); + } + + dynamic_heap_count_data.last_n_heaps = n_heaps; + } +#endif //DYNAMIC_HEAP_COUNT + suspended_start_time = GetHighPrecisionTimeStamp(); BEGIN_TIMING(suspend_ee_during_log); + dprintf (9999, ("h0 suspending EE in GC!")); GCToEEInterface::SuspendEE(SUSPEND_FOR_GC); + dprintf (9999, ("h0 suspended EE in GC!")); END_TIMING(suspend_ee_during_log); proceed_with_gc_p = TRUE; @@ -7067,46 +7153,74 @@ void gc_heap::gc_thread_function () { settings.init_mechanisms(); #ifdef DYNAMIC_HEAP_COUNT - // make sure the other gc threads cannot see this as a request to change heap count - // see explanation below about the cases when we return from gc_start_event.Wait - assert (dynamic_heap_count_data.new_n_heaps == n_heaps); + if (gc_heap::dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) + { + // make sure the other gc threads cannot see this as a request to change heap count + // see explanation below about the cases when we return from gc_start_event.Wait + assert (dynamic_heap_count_data.new_n_heaps == n_heaps); + } #endif //DYNAMIC_HEAP_COUNT + dprintf (9999, ("GC thread %d setting_gc_start_in_gc(h%d)", heap_number, n_heaps)); gc_start_event.Set(); } dprintf (3, (ThreadStressLog::gcServerThread0StartMsg(), heap_number)); } else { + dprintf (9999, ("GC thread %d waiting_for_gc_start(%d)(gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier(&settings.gc_index))); gc_start_event.Wait(INFINITE, FALSE); #ifdef DYNAMIC_HEAP_COUNT - // we have a couple different cases to handle here when we come back from the wait: - // 1. We are starting a GC. Signaled by dynamic_heap_count_data.new_n_heaps == n_heaps - // a) We are starting a GC, but this thread is idle. Signaled by n_heaps <= heap_number - // b) We are starting a GC, and this thread is participating. Signaled by heap_number < n_heaps - // 2. We are changing heap count. Signaled by dynamic_heap_count_data.new_n_heaps != n_heaps - // a) We are changing heap count, but this thread is idle. Signaled by n_heaps <= heap_number. - // b) We are changing heap count, and this thread is participating. Signaled by heap_number < n_heaps. - - // check for 1.a) and 2.a) cases above - if (n_heaps <= heap_number) - { - dprintf (2, ("GC thread %d idle", heap_number)); - - // make sure GC is complete so we know the gc_idle_thread_event has been reset - g_theGCHeap->WaitUntilGCComplete(); + dprintf (9999, ("GC thread %d waiting_done_gc_start(%d-%d)(i: %d)(gc%Id)", + heap_number, n_heaps, dynamic_heap_count_data.new_n_heaps, dynamic_heap_count_data.init_only_p, VolatileLoadWithoutBarrier (&settings.gc_index))); + + if ((gc_heap::dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) && + (dynamic_heap_count_data.new_n_heaps != n_heaps)) + { + // The reason why we need to do this is - + // + for threads that were participating, we need them to do work for change_heap_count + // + for threads that were not participating but will need to participate, we need to make sure they are woken now instead of + // randomly sometime later. + int old_n_heaps = n_heaps; + int new_n_heaps = dynamic_heap_count_data.new_n_heaps; + int num_threads_to_wake = max (new_n_heaps, old_n_heaps); + if (heap_number < num_threads_to_wake) + { + dprintf (9999, ("h%d < %d, calling change", heap_number, num_threads_to_wake)); + change_heap_count (dynamic_heap_count_data.new_n_heaps); + if (new_n_heaps < old_n_heaps) + { + dprintf (9999, ("h%d after change", heap_number)); + // at the end of change_heap_count we've changed join's heap count to the new one if it's smaller. So we need to make sure + // only that many threads will participate in the following GCs. + if (heap_number < new_n_heaps) + { + dprintf (9999, ("h%d < %d participating (dec)", heap_number, new_n_heaps)); + } + else + { + Interlocked::Increment (&dynamic_heap_count_data.idle_thread_count); + dprintf (9999, ("GC thread %d wait_on_idle(%d < %d)(gc%Id), total idle %d", heap_number, old_n_heaps, new_n_heaps, + VolatileLoadWithoutBarrier (&settings.gc_index), VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); + gc_idle_thread_event.Wait (INFINITE, FALSE); + dprintf (9999, ("GC thread %d waking_from_idle(%d)(gc%Id) after doing change", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); + } + } + else + { + dprintf (9999, ("h%d < %d participating (inc)", heap_number, new_n_heaps)); + } + } + else + { + Interlocked::Increment (&dynamic_heap_count_data.idle_thread_count); + dprintf (9999, ("GC thread %d wait_on_idle(< max %d)(gc%Id), total idle %d", heap_number, num_threads_to_wake, + VolatileLoadWithoutBarrier (&settings.gc_index), VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); + gc_idle_thread_event.Wait (INFINITE, FALSE); + dprintf (9999, ("GC thread %d waking_from_idle(%d)(gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); + } - // now wait on the gc_idle_thread_event - gc_idle_thread_event.Wait(INFINITE, FALSE); - dprintf (2, ("GC thread %d waking from idle", heap_number)); - continue; - } - // case 2.b) above: is this a request to change heap count? - if (dynamic_heap_count_data.new_n_heaps != n_heaps) - { - change_heap_count (dynamic_heap_count_data.new_n_heaps); continue; } - // case 1.b) above: we're starting a GC. #endif //DYNAMIC_HEAP_COUNT dprintf (3, (ThreadStressLog::gcServerThreadNStartMsg(), heap_number)); } @@ -7191,10 +7305,6 @@ void gc_heap::gc_thread_function () { gradual_decommit_in_progress_p = decommit_step (DECOMMIT_TIME_STEP_MILLISECONDS); } -#ifdef DYNAMIC_HEAP_COUNT - // check if we should adjust the number of heaps - check_heap_count(); -#endif //DYNAMIC_HEAP_COUNT } else { @@ -12527,6 +12637,16 @@ void gc_heap::rearrange_uoh_segments() freeable_uoh_segment = 0; } +void gc_heap::delay_free_segments() +{ + rearrange_uoh_segments(); +#ifdef BACKGROUND_GC + background_delay_delete_uoh_segments(); + if (!gc_heap::background_running_p()) + rearrange_small_heap_segments(); +#endif //BACKGROUND_GC +} + #ifndef USE_REGIONS void gc_heap::rearrange_heap_segments(BOOL compacting) { @@ -14860,6 +14980,25 @@ gc_heap::init_gc_heap (int h_number) gc_done_event_lock = -1; gc_done_event_set = false; +#ifdef DYNAMIC_HEAP_COUNT + if (h_number != 0) + { + if (!gc_idle_thread_event.CreateAutoEventNoThrow (FALSE)) + { + return 0; + } + +#ifdef BACKGROUND_GC + if (!bgc_idle_thread_event.CreateAutoEventNoThrow (FALSE)) + { + return 0; + } +#endif //BACKGROUND_GC + + dprintf (9999, ("creating idle events for h%d", h_number)); + } +#endif //DYNAMIC_HEAP_COUNT + if (!init_dynamic_data()) { return 0; @@ -16038,7 +16177,6 @@ void min_fl_list_info::thread_item_no_prev (uint8_t* item) tail = item; } -// This is only implemented for gen2 right now!!!! // the min_fl_list array is arranged as chunks of n_heaps min_fl_list_info, the 1st chunk corresponds to the 1st bucket, // and so on. void allocator::rethread_items (size_t* num_total_fl_items, size_t* num_total_fl_items_rethreaded, gc_heap* current_heap, @@ -17406,6 +17544,7 @@ BOOL gc_heap::a_fit_free_list_uoh_p (size_t size, gen_number, align_const); dd_new_allocation (dynamic_data_of (gen_number)) -= limit; + size_t saved_free_list_size = free_list_size; #ifdef FEATURE_LOH_COMPACTION if (loh_pad) { @@ -17434,7 +17573,7 @@ BOOL gc_heap::a_fit_free_list_uoh_p (size_t size, { generation_free_obj_space (gen) += remain_size; } - generation_free_list_space (gen) -= free_list_size; + generation_free_list_space (gen) -= saved_free_list_size; assert ((ptrdiff_t)generation_free_list_space (gen) >= 0); generation_free_list_allocated (gen) += limit; @@ -22000,11 +22139,70 @@ BOOL gc_heap::should_proceed_with_gc() void gc_heap::update_end_gc_time_per_heap() { +#ifdef DYNAMIC_HEAP_COUNT + size_t prev_gen2_end_time = 0; + if ((heap_number == 0) && (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes) && (settings.condemned_generation == max_generation)) + { + dynamic_data* dd = dynamic_data_of (max_generation); + prev_gen2_end_time = dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd);; + } +#endif //DYNAMIC_HEAP_COUNT + for (int gen_number = 0; gen_number <= settings.condemned_generation; gen_number++) { dynamic_data* dd = dynamic_data_of (gen_number); + + if (heap_number == 0) + { + dprintf (6666, ("prev gen%d GC end time: prev start %I64d + prev gc elapsed %Id = %I64d", + gen_number, dd_previous_time_clock (dd), dd_gc_elapsed_time (dd), (dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd)))); + } + dd_gc_elapsed_time (dd) = (size_t)(end_gc_time - dd_time_clock (dd)); + + if (heap_number == 0) + { + dprintf (6666, ("updated NGC%d %Id elapsed time to %I64d - %I64d = %I64d", gen_number, dd_gc_clock (dd), end_gc_time, dd_time_clock (dd), dd_gc_elapsed_time (dd))); + } + } + +#ifdef DYNAMIC_HEAP_COUNT + if ((heap_number == 0) && (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes)) + { + dynamic_heap_count_data_t::sample& sample = dynamic_heap_count_data.samples[dynamic_heap_count_data.sample_index]; + sample.elapsed_between_gcs = end_gc_time - last_suspended_end_time; + sample.gc_pause_time = dd_gc_elapsed_time (dynamic_data_of (0)); + sample.msl_wait_time = get_msl_wait_time(); + + dprintf (6666, ("sample#%d: this GC end %I64d - last sus end %I64d = %I64d, this GC pause %I64d, msl wait %I64d", + dynamic_heap_count_data.sample_index, end_gc_time, last_suspended_end_time, sample.elapsed_between_gcs, sample.gc_pause_time, sample.msl_wait_time)); + + last_suspended_end_time = end_gc_time; + + GCEventFireHeapCountSample_V1 ( + (uint64_t)VolatileLoadWithoutBarrier (&settings.gc_index), + sample.elapsed_between_gcs, + sample.gc_pause_time, + sample.msl_wait_time); + + dynamic_heap_count_data.sample_index = (dynamic_heap_count_data.sample_index + 1) % dynamic_heap_count_data_t::sample_size; + + if (settings.condemned_generation == max_generation) + { + gc_index_full_gc_end = dd_gc_clock (dynamic_data_of (0)); + size_t elapsed_between_gen2_gcs = end_gc_time - prev_gen2_end_time; + size_t gen2_elapsed_time = sample.gc_pause_time; + dynamic_heap_count_data.gen2_gc_percents[dynamic_heap_count_data.gen2_sample_index] = (float)gen2_elapsed_time * 100.0f / elapsed_between_gen2_gcs; + + dprintf (6666, ("gen2 sample#%d: this GC end %I64d - last gen2 end %I64d = %I64d, GC elapsed %I64d, percent %.3f", + dynamic_heap_count_data.gen2_sample_index, end_gc_time, prev_gen2_end_time, elapsed_between_gen2_gcs, + gen2_elapsed_time, dynamic_heap_count_data.gen2_gc_percents[dynamic_heap_count_data.gen2_sample_index])); + dynamic_heap_count_data.gen2_sample_index = (dynamic_heap_count_data.gen2_sample_index + 1) % dynamic_heap_count_data_t::sample_size; + } + + calculate_new_heap_count (); } +#endif //DYNAMIC_HEAP_COUNT } void gc_heap::update_end_ngc_time() @@ -22151,7 +22349,31 @@ void gc_heap::gc1() { dynamic_data* dd = dynamic_data_of (n); end_gc_time = GetHighPrecisionTimeStamp(); + size_t time_since_last_gen2 = 0; + +#ifdef DYNAMIC_HEAP_COUNT + if ((heap_number == 0) && (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes)) + { + time_since_last_gen2 = (size_t)(end_gc_time - (dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd))); + dprintf (6666, ("BGC %Id end %I64d - (prev gen2 start %I64d + elapsed %Id = %I64d) = time inbewteen gen2 %Id", + dd_gc_clock (dd), end_gc_time, dd_previous_time_clock (dd), dd_gc_elapsed_time (dd), (dd_previous_time_clock (dd) + dd_gc_elapsed_time (dd)), time_since_last_gen2)); + } +#endif //DYNAMIC_HEAP_COUNT + dd_gc_elapsed_time (dd) = (size_t)(end_gc_time - dd_time_clock (dd)); +#ifdef DYNAMIC_HEAP_COUNT + if ((heap_number == 0) && (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes)) + { + dprintf (6666, ("updating BGC %Id elapsed time to %I64d - %I64d = %I64d", dd_gc_clock (dd), end_gc_time, dd_time_clock (dd), dd_gc_elapsed_time (dd))); + + float bgc_percent = (float)dd_gc_elapsed_time (dd) * 100.0f / (float)time_since_last_gen2; + dynamic_heap_count_data.gen2_gc_percents[dynamic_heap_count_data.gen2_sample_index] = bgc_percent; + dprintf (6666, ("gen2 sample %d elapsed %Id * 100 / time inbetween gen2 %Id = %.3f", + dynamic_heap_count_data.gen2_sample_index, dd_gc_elapsed_time (dd), time_since_last_gen2, bgc_percent)); + dynamic_heap_count_data.gen2_sample_index = (dynamic_heap_count_data.gen2_sample_index + 1) % dynamic_heap_count_data_t::sample_size; + gc_index_full_gc_end = dd_gc_clock (dynamic_data_of (0)); + } +#endif //DYNAMIC_HEAP_COUNT #ifdef HEAP_BALANCE_INSTRUMENTATION if (heap_number == 0) @@ -22758,7 +22980,12 @@ void gc_heap::merge_fl_from_other_heaps (int gen_idx, int to_n_heaps, int from_n assert (free_list_space_decrease <= generation_free_list_space (gen)); generation_free_list_space (gen) -= free_list_space_decrease; - assert (free_list_space_decrease <= dd_fragmentation (dd)); + // TODO - I'm seeing for gen2 this is free_list_space_decrease can be a bit larger than frag. + // Need to fix this later. + if (gen_idx != max_generation) + { + assert (free_list_space_decrease <= dd_fragmentation (dd)); + } size_t free_list_space_increase = 0; for (int from_hn = 0; from_hn < from_n_heaps; from_hn++) @@ -23733,9 +23960,6 @@ void gc_heap::garbage_collect (int n) #ifdef MULTIPLE_HEAPS gc_start_event.Reset(); -#ifdef DYNAMIC_HEAP_COUNT - gc_idle_thread_event.Reset(); -#endif //DYNAMIC_HEAP_COUNT gc_t_join.restart(); #endif //MULTIPLE_HEAPS } @@ -23757,6 +23981,9 @@ void gc_heap::garbage_collect (int n) #endif // STRESS_HEAP #ifdef MULTIPLE_HEAPS +#ifdef STRESS_DYNAMIC_HEAP_COUNT + Interlocked::Increment (&heaps_in_this_gc); +#endif //STRESS_DYNAMIC_HEAP_COUNT //align all heaps on the max generation to condemn dprintf (3, ("Joining for max generation to condemn")); condemned_generation_num = generation_to_condemn (n, @@ -23772,30 +23999,31 @@ void gc_heap::garbage_collect (int n) #endif //FEATURE_BASICFREEZE #ifdef MULTIPLE_HEAPS +#ifdef STRESS_DYNAMIC_HEAP_COUNT + dprintf (9999, ("%d heaps, join sees %d, actually joined %d, %d idle threads (%d)", + n_heaps, gc_t_join.get_num_threads (), heaps_in_this_gc, + VolatileLoadWithoutBarrier(&dynamic_heap_count_data.idle_thread_count), (n_max_heaps - n_heaps))); + if (heaps_in_this_gc != n_heaps) + { + dprintf (9999, ("should have %d heaps but actually have %d!!", n_heaps, heaps_in_this_gc)); + GCToOSInterface::DebugBreak (); + } + + heaps_in_this_gc = 0; +#endif //STRESS_DYNAMIC_HEAP_COUNT + for (int i = 0; i < n_heaps; i++) { gc_heap* hp = g_heaps[i]; // check for card table growth if (g_gc_card_table != hp->card_table) hp->copy_brick_card_table(); - - hp->rearrange_uoh_segments(); -#ifdef BACKGROUND_GC - hp->background_delay_delete_uoh_segments(); - if (!gc_heap::background_running_p()) - hp->rearrange_small_heap_segments(); -#endif //BACKGROUND_GC + hp->delay_free_segments(); } #else //MULTIPLE_HEAPS if (g_gc_card_table != card_table) copy_brick_card_table(); - - rearrange_uoh_segments(); -#ifdef BACKGROUND_GC - background_delay_delete_uoh_segments(); - if (!gc_heap::background_running_p()) - rearrange_small_heap_segments(); -#endif //BACKGROUND_GC + delay_free_segments(); #endif //MULTIPLE_HEAPS BOOL should_evaluate_elevation = TRUE; @@ -23882,10 +24110,8 @@ void gc_heap::garbage_collect (int n) do_pre_gc(); #ifdef MULTIPLE_HEAPS + dprintf (9999, ("in GC, resetting gc_start")); gc_start_event.Reset(); -#ifdef DYNAMIC_HEAP_COUNT - gc_idle_thread_event.Reset(); -#endif //DYNAMIC_HEAP_COUNT dprintf(3, ("Starting all gc threads for gc")); gc_t_join.restart(); #endif //MULTIPLE_HEAPS @@ -24341,7 +24567,7 @@ void gc_heap::equalize_promoted_bytes(int condemned_gen_number) // hope is to achieve better work balancing in relocate and compact phases // this is also used when the heap count changes to balance regions between heaps int highest_gen_number = ((condemned_gen_number == max_generation) ? - (total_generation_count - 1) : condemned_gen_number); + (total_generation_count - 1) : condemned_gen_number); int stop_gen_idx = get_stop_generation_index (condemned_gen_number); for (int gen_idx = highest_gen_number; gen_idx >= stop_gen_idx; gen_idx--) @@ -25050,285 +25276,332 @@ void gc_heap::recommission_heap() #endif //RECORD_LOH_STATE } -void gc_heap::check_heap_count () +float median_of_3 (float a, float b, float c) { - dynamic_heap_count_data.new_n_heaps = n_heaps; +#define compare_and_swap(i, j) \ + { \ + if (i < j) \ + { \ + float t = i; \ + i = j; \ + j = t; \ + } \ + } + compare_and_swap (b, a); + compare_and_swap (c, a); + compare_and_swap (c, b); +#undef compare_and_swap + return b; +} - if (dynamic_adaptation_mode != dynamic_adaptation_to_application_sizes) +size_t gc_heap::get_num_completed_gcs () +{ + size_t num_completed_gcs = settings.gc_index; +#ifdef BACKGROUND_GC + if (g_heaps[0]->is_bgc_in_progress ()) { - return; + num_completed_gcs--; + dprintf (6666, ("BGC in prog, completed GCs -> %Id", num_completed_gcs)); } +#endif //BACKGROUND_GC - // we should be calling this only on the main GC thread - assert (heap_number == 0); + return num_completed_gcs; +} - // acquire data for the current sample - uint64_t soh_msl_wait_time = 0; - uint64_t uoh_msl_wait_time = 0; - size_t allocating_thread_count = 0; - size_t heap_size = 0; - for (int i = 0; i < n_heaps; i++) +int gc_heap::calculate_new_heap_count () +{ + assert (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes); + + size_t num_completed_gcs = get_num_completed_gcs (); + + dprintf (6666, ("current GC %Id(completed: %Id), prev completed GCs %Id, last full GC happened at index %Id", + VolatileLoadWithoutBarrier (&settings.gc_index), num_completed_gcs, dynamic_heap_count_data.prev_num_completed_gcs, gc_index_full_gc_end)); + + if (num_completed_gcs < (dynamic_heap_count_data.prev_num_completed_gcs + dynamic_heap_count_data_t::sample_size)) { - gc_heap* hp = g_heaps[i]; + dprintf (6666, ("not enough GCs, skipping")); + return n_heaps; + } - allocating_thread_count += hp->alloc_contexts_used; + float median_gen2_tcp_percent = 0.0f; + if (gc_index_full_gc_end >= (settings.gc_index - dynamic_heap_count_data_t::sample_size)) + { + median_gen2_tcp_percent = dynamic_heap_count_data.get_median_gen2_gc_percent (); + } - soh_msl_wait_time += hp->more_space_lock_soh.msl_wait_time; - hp->more_space_lock_soh.msl_wait_time = 0; - hp->more_space_lock_soh.msl_wait_count = 0; + // If there was a blocking gen2 GC, the overhead would be very large and most likely we would not pick it. So we + // rely on the gen2 sample's overhead calculated above. + float throughput_cost_percents[dynamic_heap_count_data_t::sample_size]; + for (int i = 0; i < dynamic_heap_count_data_t::sample_size; i++) + { + dynamic_heap_count_data_t::sample& sample = dynamic_heap_count_data.samples[i]; + throughput_cost_percents[i] = (sample.elapsed_between_gcs ? (((float)sample.msl_wait_time / n_heaps + sample.gc_pause_time) * 100.0f / (float)sample.elapsed_between_gcs) : 0.0f); + assert (throughput_cost_percents[i] >= 0.0); + if (throughput_cost_percents[i] > 100.0) + throughput_cost_percents[i] = 100.0; + dprintf (6666, ("sample %d: msl %I64d / %d + pause %I64d / elapsed %I64d = throughput_cost_percent: %.3f", i, + sample.msl_wait_time, n_heaps, sample.gc_pause_time, sample.elapsed_between_gcs, throughput_cost_percents[i])); + } - uoh_msl_wait_time += hp->more_space_lock_uoh.msl_wait_time; - hp->more_space_lock_uoh.msl_wait_time = 0; - hp->more_space_lock_uoh.msl_wait_count = 0; + float median_throughput_cost_percent = median_of_3 (throughput_cost_percents[0], throughput_cost_percents[1], throughput_cost_percents[2]); + + // apply exponential smoothing and use 1/3 for the smoothing factor + const float smoothing = 3; + float smoothed_median_throughput_cost_percent = dynamic_heap_count_data.smoothed_median_throughput_cost_percent; + if (smoothed_median_throughput_cost_percent != 0.0f) + { + // average it with the previous value + smoothed_median_throughput_cost_percent = median_throughput_cost_percent / smoothing + (smoothed_median_throughput_cost_percent / smoothing) * (smoothing - 1); + } + else + { + smoothed_median_throughput_cost_percent = median_throughput_cost_percent; + } + + dprintf (6666, ("median tcp: %.3f, smoothed tcp: %.3f, gen2 tcp %.3f(%.3f, %.3f, %.3f)", + median_throughput_cost_percent, smoothed_median_throughput_cost_percent, median_gen2_tcp_percent, + dynamic_heap_count_data.gen2_gc_percents[0], dynamic_heap_count_data.gen2_gc_percents[1], dynamic_heap_count_data.gen2_gc_percents[2])); + + size_t heap_size = 0; + for (int i = 0; i < n_heaps; i++) + { + gc_heap* hp = g_heaps[i]; for (int gen_idx = 0; gen_idx < total_generation_count; gen_idx++) { dynamic_data* dd = hp->dynamic_data_of (gen_idx); // estimate the size of each generation as the live data size plus the budget - heap_size += dd_promoted_size (dd) + dd_desired_allocation (dd); - dprintf (6666, ("h%d g%d promoted: %zd desired allocation: %zd", i, gen_idx, dd_promoted_size (dd), dd_desired_allocation (dd))); + heap_size += dd_current_size (dd) + dd_desired_allocation (dd); + dprintf (3, ("h%d g%d current: %zd desired allocation: %zd", i, gen_idx, dd_promoted_size (dd), dd_desired_allocation (dd))); } } - dynamic_data* hp0_dd0 = g_heaps[0]->dynamic_data_of (0); + // estimate the space cost of adding a heap as the min gen0 budget + size_t heap_space_cost_per_heap = dd_min_size (g_heaps[0]->dynamic_data_of (0)); - // persist data for the current sample - dynamic_heap_count_data_t::sample& sample = dynamic_heap_count_data.samples[dynamic_heap_count_data.sample_index]; + // compute the % space cost of adding a heap + float percent_heap_space_cost_per_heap = heap_space_cost_per_heap * 100.0f / heap_size; - sample.soh_msl_wait_time = soh_msl_wait_time / n_heaps; - sample.uoh_msl_wait_time = uoh_msl_wait_time / n_heaps; - sample.elapsed_between_gcs = dd_time_clock (hp0_dd0) - dd_previous_time_clock (hp0_dd0); - sample.gc_elapsed_time = dd_gc_elapsed_time (hp0_dd0); - sample.allocating_thread_count = allocating_thread_count; - sample.heap_size = heap_size; + // compute reasonable step sizes for the heap count + // + // on the way up, we essentially multiply the heap count by 1.5, so we go 1, 2, 3, 5, 8 ... + // we don't go all the way to the number of CPUs, but stay 1 or 2 short + int step_up = (n_heaps + 1) / 2; + int extra_heaps = 1 + (n_max_heaps >= 32); + step_up = min (step_up, n_max_heaps - extra_heaps - n_heaps); - dprintf (6666, ("sample %d: soh_msl_wait_time: %zd, uoh_msl_wait_time: %zd, elapsed_between_gcs: %zd, gc_elapsed_time: %d, heap_size: %zd MB", - dynamic_heap_count_data.sample_index, - sample.soh_msl_wait_time, - sample.uoh_msl_wait_time, - sample.elapsed_between_gcs, - sample.gc_elapsed_time, - sample.heap_size/(1024*1024))); + // on the way down, we essentially divide the heap count by 1.5 + int step_down = (n_heaps + 1) / 3; - dynamic_heap_count_data.sample_index = (dynamic_heap_count_data.sample_index + 1) % dynamic_heap_count_data_t::sample_size; + // estimate the potential time benefit of going up a step + float tcp_reduction_per_step_up = smoothed_median_throughput_cost_percent * step_up / (n_heaps + step_up); - GCEventFireHeapCountSample_V1( - sample.gc_elapsed_time, - sample.soh_msl_wait_time, - sample.uoh_msl_wait_time, - sample.elapsed_between_gcs - ); + // estimate the potential time cost of going down a step + float tcp_increase_per_step_down = smoothed_median_throughput_cost_percent * step_down / (n_heaps - step_down); + + // estimate the potential space cost of going up a step + float scp_increase_per_step_up = percent_heap_space_cost_per_heap * step_up; - if (settings.gc_index < prev_change_heap_count_gc_index + 3) + // estimate the potential space saving of going down a step + float scp_decrease_per_step_down = percent_heap_space_cost_per_heap * step_down; + + dprintf (6666, ("[CHP] u %d, d %d | space cost %Id / heap %Id(%.2fmb) = scp %.3f (u: %.3f, d: %.3f) | stcp %.3f, u * %.1f = %.3f, d * %.1f = %.3f", + step_up, step_down, + heap_space_cost_per_heap, heap_size, ((float)heap_size / (float)1000 / (float)1000), percent_heap_space_cost_per_heap, + scp_increase_per_step_up, scp_decrease_per_step_down, + smoothed_median_throughput_cost_percent, + ((float)step_up / (float)(n_heaps + step_up)), tcp_reduction_per_step_up, + ((float)step_down / (float)(n_heaps - step_down)), tcp_increase_per_step_down)); + +#ifdef STRESS_DYNAMIC_HEAP_COUNT + // quick hack for initial testing + int new_n_heaps = (int)gc_rand::get_rand (n_max_heaps - 1) + 1; + + // if we are adjusting down, make sure we adjust lower than the lowest uoh msl heap + if ((new_n_heaps < n_heaps) && (dynamic_heap_count_data.lowest_heap_with_msl_uoh != -1)) { - // reconsider the decision every few gcs - return; + new_n_heaps = min (dynamic_heap_count_data.lowest_heap_with_msl_uoh, new_n_heaps); + new_n_heaps = max (new_n_heaps, 1); } - - if (gc_heap::background_running_p()) + dprintf (6666, ("stress %d -> %d", n_heaps, new_n_heaps)); +#else //STRESS_DYNAMIC_HEAP_COUNT + int new_n_heaps = n_heaps; + if (median_throughput_cost_percent > 10.0f) { - // can't have background gc running while we change the number of heaps - // so it's useless to compute a new number of heaps here + // ramp up more agressively - use as many heaps as it would take to bring + // the tcp down to 5% + new_n_heaps = (int)(n_heaps * (median_throughput_cost_percent / 5.0)); + dprintf (6666, ("[CHP0] tcp %.3f -> %d * %.3f = %d", median_throughput_cost_percent, n_heaps, (median_throughput_cost_percent / 5.0), new_n_heaps)); + new_n_heaps = min (new_n_heaps, n_max_heaps - extra_heaps); } - else + // if the median tcp is 10% or less, react slower + else if ((smoothed_median_throughput_cost_percent > 5.0f) || (median_gen2_tcp_percent > 10.0f)) { - // compute the % overhead from msl waiting time and gc time for each of the samples - float percent_overhead[dynamic_heap_count_data_t::sample_size]; - for (int i = 0; i < dynamic_heap_count_data_t::sample_size; i++) - { - dynamic_heap_count_data_t::sample& sample = dynamic_heap_count_data.samples[i]; - uint64_t overhead_time = sample.soh_msl_wait_time + sample.uoh_msl_wait_time + sample.gc_elapsed_time; - percent_overhead[i] = overhead_time * 100.0f / sample.elapsed_between_gcs; - if (percent_overhead[i] < 0) - percent_overhead[i] = 0; - else if (percent_overhead[i] > 100) - percent_overhead[i] = 100; - dprintf (6666, ("sample %d: percent_overhead: %d%%", i, (int)percent_overhead[i])); - } - // compute the median of the percent overhead samples - #define compare_and_swap(i, j) \ - { \ - if (percent_overhead[i] < percent_overhead[j]) \ - { \ - float t = percent_overhead[i]; \ - percent_overhead[i] = percent_overhead[j]; \ - percent_overhead[j] = t; \ - } \ - } - compare_and_swap (1, 0); - compare_and_swap (2, 0); - compare_and_swap (2, 1); - #undef compare_and_swap - - // the middle element is the median overhead percentage - float median_percent_overhead = percent_overhead[1]; - - // apply exponential smoothing and use 1/3 for the smoothing factor - const float smoothing = 3; - float smoothed_median_percent_overhead = dynamic_heap_count_data.smoothed_median_percent_overhead; - if (smoothed_median_percent_overhead != 0.0f) - { - // average it with the previous value - smoothed_median_percent_overhead = median_percent_overhead / smoothing + (smoothed_median_percent_overhead / smoothing) * (smoothing - 1); + if (smoothed_median_throughput_cost_percent > 5.0f) + { + dprintf (6666, ("[CHP1] stcp %.3f > 5, %d + %d = %d", smoothed_median_throughput_cost_percent, n_heaps, step_up, (n_heaps + step_up))); } else { - // first time? initialize to the median - smoothed_median_percent_overhead = median_percent_overhead; + dprintf (6666, ("[CHP2] tcp %.3f > 10, %d + %d = %d", median_gen2_tcp_percent, n_heaps, step_up, (n_heaps + step_up))); } + new_n_heaps += step_up; + } + // if we can save at least 1% more in time than we spend in space, increase number of heaps + else if ((tcp_reduction_per_step_up - scp_increase_per_step_up) >= 1.0f) + { + dprintf (6666, ("[CHP3] % .3f - % .3f = % .3f, % d + % d = % d", + tcp_reduction_per_step_up, scp_increase_per_step_up, (tcp_reduction_per_step_up - scp_increase_per_step_up), + n_heaps, step_up, (n_heaps + step_up))); + new_n_heaps += step_up; + } + // if we can save at least 1% more in space than we spend in time, decrease number of heaps + else if ((smoothed_median_throughput_cost_percent < 1.0f) && + (median_gen2_tcp_percent < 5.0f) && + ((scp_decrease_per_step_down - tcp_increase_per_step_down) >= 1.0f)) + { + dprintf (6666, ("[CHP4] stcp %.3f tcp %.3f, %.3f - %.3f = %.3f, %d + %d = %d", + smoothed_median_throughput_cost_percent, median_gen2_tcp_percent, + scp_decrease_per_step_down, tcp_increase_per_step_down, (scp_decrease_per_step_down - tcp_increase_per_step_down), + n_heaps, step_up, (n_heaps + step_up))); + new_n_heaps -= step_down; + } - dprintf (6666, ("median overhead: %d%% smoothed median overhead: %d%%", (int)(median_percent_overhead*1000), (int)(smoothed_median_percent_overhead*1000))); - - // estimate the space cost of adding a heap as the min gen0 size - size_t heap_space_cost_per_heap = dd_min_size (hp0_dd0); - - // compute the % space cost of adding a heap - float percent_heap_space_cost_per_heap = heap_space_cost_per_heap * 100.0f / heap_size; - - // compute reasonable step sizes for the heap count + assert (new_n_heaps >= 1); + assert (new_n_heaps <= n_max_heaps); +#endif //STRESS_DYNAMIC_HEAP_COUNT - // on the way up, we essentially multiply the heap count by 1.5, so we go 1, 2, 3, 5, 8 ... - // we don't go all the way to the number of CPUs, but stay 1 or 2 short - int step_up = (n_heaps + 1) / 2; - int extra_heaps = 1 + (n_max_heaps >= 32); - step_up = min (step_up, n_max_heaps - extra_heaps - n_heaps); + // store data used for decision to emit in ETW event + dynamic_heap_count_data.median_throughput_cost_percent = median_throughput_cost_percent; + dynamic_heap_count_data.smoothed_median_throughput_cost_percent = smoothed_median_throughput_cost_percent; + dynamic_heap_count_data.percent_heap_space_cost_per_heap = percent_heap_space_cost_per_heap; + dynamic_heap_count_data.tcp_reduction_per_step_up = tcp_reduction_per_step_up; + dynamic_heap_count_data.tcp_increase_per_step_down = tcp_increase_per_step_down; + dynamic_heap_count_data.scp_increase_per_step_up = scp_increase_per_step_up; + dynamic_heap_count_data.scp_decrease_per_step_down = scp_decrease_per_step_down; + + GCEventFireHeapCountTuning_V1 ( + (uint16_t)dynamic_heap_count_data.new_n_heaps, + (uint64_t)VolatileLoadWithoutBarrier (&settings.gc_index), + dynamic_heap_count_data.median_throughput_cost_percent, + dynamic_heap_count_data.smoothed_median_throughput_cost_percent, + dynamic_heap_count_data.tcp_reduction_per_step_up, + dynamic_heap_count_data.tcp_increase_per_step_down, + dynamic_heap_count_data.scp_increase_per_step_up, + dynamic_heap_count_data.scp_decrease_per_step_down + ); - // on the way down, we essentially divide the heap count by 1.5 - int step_down = (n_heaps + 1) / 3; + dynamic_heap_count_data.prev_num_completed_gcs = num_completed_gcs; - // estimate the potential time benefit of going up a step - float overhead_reduction_per_step_up = smoothed_median_percent_overhead * step_up / (n_heaps + step_up); + if (new_n_heaps != n_heaps) + { + dprintf (6666, ("should change! %d->%d", n_heaps, new_n_heaps)); + dynamic_heap_count_data.heap_count_to_change_to = new_n_heaps; + dynamic_heap_count_data.should_change_heap_count = true; + } - // estimate the potential time cost of going down a step - float overhead_increase_per_step_down = smoothed_median_percent_overhead * step_down / (n_heaps - step_down); + return new_n_heaps; +} - // estimate the potential space cost of going up a step - float space_cost_increase_per_step_up = percent_heap_space_cost_per_heap * step_up; +void gc_heap::check_heap_count () +{ + dynamic_heap_count_data.new_n_heaps = dynamic_heap_count_data.heap_count_to_change_to; - // estimate the potential space saving of going down a step - float space_cost_decrease_per_step_down = percent_heap_space_cost_per_heap * step_down; + assert (dynamic_heap_count_data.new_n_heaps != n_heaps); -#ifdef STRESS_DYNAMIC_HEAP_COUNT - // quick hack for initial testing - int new_n_heaps = (int)gc_rand::get_rand (n_max_heaps - 1) + 1; + if (dynamic_heap_count_data.new_n_heaps != n_heaps) + { + dprintf (9999, ("h0 suspending EE in check")); + // can't have threads allocating while we change the number of heaps + GCToEEInterface::SuspendEE(SUSPEND_FOR_GC_PREP); + dprintf (9999, ("h0 suspended EE in check")); - // if we are adjusting down, make sure we adjust lower than the lowest uoh msl heap - if ((new_n_heaps < n_heaps) && (dynamic_heap_count_data.lowest_heap_with_msl_uoh != -1)) +#ifdef BACKGROUND_GC + if (gc_heap::background_running_p()) { - new_n_heaps = min (dynamic_heap_count_data.lowest_heap_with_msl_uoh, new_n_heaps); + // background GC is running - reset the new heap count + dynamic_heap_count_data.new_n_heaps = n_heaps; + dprintf (6666, ("can't change heap count! BGC in progress")); - // but not down to zero, obviously... - new_n_heaps = max (new_n_heaps, 1); - } -#else //STRESS_DYNAMIC_HEAP_COUNT - int new_n_heaps = n_heaps; - if (median_percent_overhead > 10.0f) - { - // ramp up more agressively - use as many heaps as it would take to bring - // the overhead down to 5% - new_n_heaps = (int)(n_heaps * (median_percent_overhead / 5.0)); - new_n_heaps = min (new_n_heaps, n_max_heaps - extra_heaps); - } - // if the median overhead is 10% or less, react slower - else if (smoothed_median_percent_overhead > 5.0f) - { - new_n_heaps += step_up; - } - // if we can save at least 1% more in time than we spend in space, increase number of heaps - else if (overhead_reduction_per_step_up - space_cost_increase_per_step_up >= 1.0f) - { - new_n_heaps += step_up; - } - // if we can save at least 1% more in space than we spend in time, decrease number of heaps - else if (smoothed_median_percent_overhead < 1.0f && space_cost_decrease_per_step_down - overhead_increase_per_step_down >= 1.0f) - { - new_n_heaps -= step_down; + GCToEEInterface::RestartEE(TRUE); } +#endif //BACKGROUND_GC + } - dprintf (6666, ("or: %d, si: %d, sd: %d, oi: %d => %d -> %d", - (int)overhead_reduction_per_step_up, - (int)space_cost_increase_per_step_up, - (int)space_cost_decrease_per_step_down, - (int)overhead_increase_per_step_down, - n_heaps, - new_n_heaps)); - - assert (1 <= new_n_heaps); - assert (new_n_heaps <= n_max_heaps); -#endif //STRESS_DYNAMIC_HEAP_COUNT - - dynamic_heap_count_data.new_n_heaps = new_n_heaps; - - // store data used for decision to emit in ETW event - dynamic_heap_count_data.median_percent_overhead = median_percent_overhead; - dynamic_heap_count_data.smoothed_median_percent_overhead = smoothed_median_percent_overhead; - dynamic_heap_count_data.percent_heap_space_cost_per_heap = percent_heap_space_cost_per_heap; - dynamic_heap_count_data.overhead_reduction_per_step_up = overhead_reduction_per_step_up; - dynamic_heap_count_data.overhead_increase_per_step_down = overhead_increase_per_step_down; - dynamic_heap_count_data.space_cost_increase_per_step_up = space_cost_increase_per_step_up; - dynamic_heap_count_data.space_cost_decrease_per_step_down = space_cost_decrease_per_step_down; - - GCEventFireHeapCountTuning_V1( - (uint16_t)dynamic_heap_count_data.new_n_heaps, - (uint64_t)VolatileLoad(&settings.gc_index), - dynamic_heap_count_data.median_percent_overhead, - dynamic_heap_count_data.smoothed_median_percent_overhead, - dynamic_heap_count_data.overhead_reduction_per_step_up, - dynamic_heap_count_data.overhead_increase_per_step_down, - dynamic_heap_count_data.space_cost_increase_per_step_up, - dynamic_heap_count_data.space_cost_decrease_per_step_down - ); - - if (new_n_heaps != n_heaps) + if (dynamic_heap_count_data.new_n_heaps != n_heaps) + { + dprintf (6666, ("prep to change from %d to %d", n_heaps, dynamic_heap_count_data.new_n_heaps)); + if (!prepare_to_change_heap_count (dynamic_heap_count_data.new_n_heaps)) { - // can't have threads allocating while we change the number of heaps - GCToEEInterface::SuspendEE(SUSPEND_FOR_GC_PREP); - - if (gc_heap::background_running_p()) - { - // background GC is running - reset the new heap count - dynamic_heap_count_data.new_n_heaps = n_heaps; - - GCToEEInterface::RestartEE(TRUE); - } + // we don't have sufficient resources - reset the new heap count + dynamic_heap_count_data.new_n_heaps = n_heaps; } } if (dynamic_heap_count_data.new_n_heaps == n_heaps) { // heap count stays the same, no work to do - dprintf (6666, ("heap count stays the same, no work to do %d == %d", dynamic_heap_count_data.new_n_heaps, n_heaps)); + dynamic_heap_count_data.prev_num_completed_gcs = get_num_completed_gcs (); + dynamic_heap_count_data.should_change_heap_count = false; - // come back after 3 GCs to reconsider - prev_change_heap_count_gc_index = settings.gc_index; + dprintf (6666, ("heap count stays the same %d, no work to do, set prev completed to %Id", dynamic_heap_count_data.new_n_heaps, dynamic_heap_count_data.prev_num_completed_gcs)); return; } - if (GCScan::GetGcRuntimeStructuresValid()) + int new_n_heaps = dynamic_heap_count_data.new_n_heaps; + + assert (!(dynamic_heap_count_data.init_only_p)); + { + // At this point we are guaranteed to be able to change the heap count to the new one. + // Change the heap count for joins here because we will need to join new_n_heaps threads together. + dprintf (9999, ("changing join hp %d->%d", n_heaps, new_n_heaps)); + int max_threads_to_wake = max (n_heaps, new_n_heaps); + gc_t_join.update_n_threads (max_threads_to_wake); + // make sure the other gc threads cannot see this as a request to GC assert (dynamic_heap_count_data.new_n_heaps != n_heaps); + + if (n_heaps < new_n_heaps) + { + int saved_idle_thread_count = dynamic_heap_count_data.idle_thread_count; + Interlocked::ExchangeAdd (&dynamic_heap_count_data.idle_thread_count, (n_heaps - new_n_heaps)); + dprintf (9999, ("GC thread %d setting idle events for h%d-h%d, total idle %d -> %d", heap_number, n_heaps, (new_n_heaps - 1), + saved_idle_thread_count, VolatileLoadWithoutBarrier (&dynamic_heap_count_data.idle_thread_count))); + + for (int heap_idx = n_heaps; heap_idx < new_n_heaps; heap_idx++) + { + g_heaps[heap_idx]->gc_idle_thread_event.Set(); +#ifdef BACKGROUND_GC + g_heaps[heap_idx]->bgc_idle_thread_event.Set(); +#endif //BACKGROUND_GC + } + } + gc_start_event.Set(); } int old_n_heaps = n_heaps; + (dynamic_heap_count_data.heap_count_change_count)++; change_heap_count (dynamic_heap_count_data.new_n_heaps); GCToEEInterface::RestartEE(TRUE); - prev_change_heap_count_gc_index = settings.gc_index; + dprintf (9999, ("h0 restarted EE")); // we made changes to the heap count that will change the overhead, // so change the smoothed overhead to reflect that - int new_n_heaps = n_heaps; - dynamic_heap_count_data.smoothed_median_percent_overhead = dynamic_heap_count_data.smoothed_median_percent_overhead/new_n_heaps*old_n_heaps; + dynamic_heap_count_data.smoothed_median_throughput_cost_percent = dynamic_heap_count_data.smoothed_median_throughput_cost_percent / n_heaps * old_n_heaps; + + dprintf (6666, ("h0 finished changing, set should change to false!")); + dynamic_heap_count_data.should_change_heap_count = false; } bool gc_heap::prepare_to_change_heap_count (int new_n_heaps) { - dprintf (6666, ("trying to change heap count %d -> %d", n_heaps, new_n_heaps)); + dprintf (9999, ("trying to change heap count %d -> %d", n_heaps, new_n_heaps)); // use this variable for clarity - n_heaps will change during the transition int old_n_heaps = n_heaps; @@ -25371,6 +25644,17 @@ bool gc_heap::prepare_to_change_heap_count (int new_n_heaps) } } + // Before we look at whether we have sufficient regions we should return regions that should be deleted to free + // so we don't lose them when we decommission heaps. We could do this for only heaps that we are about + // to decomission. But it's better to do this for all heaps because we don't need to worry about adding them to the + // heaps remain (freeable uoh/soh regions) and we get rid of regions with the heap_segment_flags_uoh_delete flag + // because background_delay_delete_uoh_segments makes the assumption it can't be the start region. + for (int i = 0; i < old_n_heaps; i++) + { + gc_heap* hp = g_heaps[i]; + hp->delay_free_segments (); + } + // if we want to increase the number of heaps, we have to make sure we can give // each heap a region for each generation. If we cannot do that, we have to give up ptrdiff_t region_count_in_gen[total_generation_count]; @@ -25451,39 +25735,34 @@ bool gc_heap::prepare_to_change_heap_count (int new_n_heaps) bool gc_heap::change_heap_count (int new_n_heaps) { + dprintf (9999, ("BEG heap%d changing %d->%d", heap_number, n_heaps, new_n_heaps)); + // use this variable for clarity - n_heaps will change during the transition int old_n_heaps = n_heaps; + bool init_only_p = dynamic_heap_count_data.init_only_p; - if (heap_number == 0) { - if (!prepare_to_change_heap_count (new_n_heaps)) - { - // we don't have sufficient resources - reset the new heap count - dynamic_heap_count_data.new_n_heaps = n_heaps; - } - } - - if (GCScan::GetGcRuntimeStructuresValid()) - { - // join for sufficient resources decision gc_t_join.join (this, gc_join_merge_temp_fl); if (gc_t_join.joined ()) { + // BGC is not running, we can safely change its join's heap count. +#ifdef BACKGROUND_GC + bgc_t_join.update_n_threads (new_n_heaps); +#endif //BACKGROUND_GC + + dynamic_heap_count_data.init_only_p = false; + dprintf (9999, ("in change h%d resetting gc_start, update bgc join to %d heaps", heap_number, new_n_heaps)); gc_start_event.Reset(); gc_t_join.restart (); } } - // gc_heap::n_heaps may have changed by now, compare to the snapshot *before* the join - if (dynamic_heap_count_data.new_n_heaps == old_n_heaps) - { - dprintf (6666, ("failed to change heap count, no work to do %d == %d", dynamic_heap_count_data.new_n_heaps, old_n_heaps)); - return false; - } + assert (dynamic_heap_count_data.new_n_heaps != old_n_heaps); + + dprintf (9999, ("Waiting h0 heap%d changing %d->%d", heap_number, n_heaps, new_n_heaps)); if (heap_number == 0) { - // after having checked for sufficient resources, we are now committed to actually change the heap count dprintf (3, ("switching heap count from %d to %d heaps", old_n_heaps, new_n_heaps)); // spread finalization data out to heaps coming into service @@ -25504,17 +25783,23 @@ bool gc_heap::change_heap_count (int new_n_heaps) from_heap_number = (from_heap_number + 1) % old_n_heaps; } - // prepare for the switch by fixing the allocation contexts on the old heaps, + // prepare for the switch by fixing the allocation contexts on the old heaps, unify the gen0_bricks_cleared flag, // and setting the survived size for the existing regions to their allocated size + BOOL unified_gen0_bricks_cleared = TRUE; for (int i = 0; i < old_n_heaps; i++) { gc_heap* hp = g_heaps[i]; - if (GCScan::GetGcRuntimeStructuresValid()) + if (!init_only_p) { hp->fix_allocation_contexts (TRUE); } + if (unified_gen0_bricks_cleared && (hp->gen0_bricks_cleared == FALSE)) + { + unified_gen0_bricks_cleared = FALSE; + } + for (int gen_idx = 0; gen_idx < total_generation_count; gen_idx++) { generation* gen = hp->generation_of (gen_idx); @@ -25614,7 +25899,7 @@ bool gc_heap::change_heap_count (int new_n_heaps) hpd->free_regions[kind].transfer_regions(&hp->free_regions[kind]); } } - // update number of heaps + dprintf (9999, ("h%d changing %d->%d", heap_number, n_heaps, new_n_heaps)); n_heaps = new_n_heaps; // even out the regions over the current number of heaps @@ -25625,6 +25910,8 @@ bool gc_heap::change_heap_count (int new_n_heaps) { gc_heap* hp = g_heaps[i]; + hp->gen0_bricks_cleared = unified_gen0_bricks_cleared; + // establish invariants regarding the ephemeral segment generation* gen0 = hp->generation_of (0); if ((hp->ephemeral_heap_segment == nullptr) || @@ -25653,7 +25940,9 @@ bool gc_heap::change_heap_count (int new_n_heaps) } } - if (GCScan::GetGcRuntimeStructuresValid()) + dprintf (3, ("individual heap%d changing %d->%d", heap_number, n_heaps, new_n_heaps)); + + if (!init_only_p) { // join for rethreading the free lists gc_t_join.join (this, gc_join_merge_temp_fl); @@ -25665,7 +25954,11 @@ bool gc_heap::change_heap_count (int new_n_heaps) // rethread the free lists for (int gen_idx = 0; gen_idx < total_generation_count; gen_idx++) { - rethread_fl_items (gen_idx); + if (heap_number < old_n_heaps) + { + dprintf (3, ("h%d calling per heap work!", heap_number)); + rethread_fl_items (gen_idx); + } // join for merging the free lists gc_t_join.join (this, gc_join_merge_temp_fl); @@ -25676,18 +25969,14 @@ bool gc_heap::change_heap_count (int new_n_heaps) gc_t_join.restart (); } } +#ifdef BACKGROUND_GC // there should be no items in the bgc_alloc_lock bgc_alloc_lock->check(); +#endif //BACKGROUND_GC } if (heap_number == 0) { - // udate the number of heaps in the joins - gc_t_join.update_n_threads(new_n_heaps); - #ifdef BACKGROUND_GC - bgc_t_join.update_n_threads(new_n_heaps); - #endif //BACKGROUND_GC - // compute the total budget per generation over the old heaps // and figure out what the new budget per heap is ptrdiff_t budget_per_heap[total_generation_count]; @@ -25747,21 +26036,50 @@ bool gc_heap::change_heap_count (int new_n_heaps) hp->decommission_heap(); } - if (GCScan::GetGcRuntimeStructuresValid()) + if (!init_only_p) { // make sure no allocation contexts point to idle heaps fix_allocation_contexts_heaps(); } - if (old_n_heaps < new_n_heaps) + dynamic_heap_count_data.last_n_heaps = old_n_heaps; + } + + // join the last time to change the heap count again if needed. + if (new_n_heaps < old_n_heaps) + { + gc_t_join.join (this, gc_join_merge_temp_fl); + if (gc_t_join.joined ()) { - // wake up threads for the new heaps - gc_idle_thread_event.Set(); + dprintf (9999, ("now changing the join heap count to the smaller one %d", new_n_heaps)); + gc_t_join.update_n_threads (new_n_heaps); + + gc_t_join.restart (); } } return true; } + +size_t gc_heap::get_msl_wait_time() +{ + assert (dynamic_adaptation_mode == dynamic_adaptation_to_application_sizes); + + size_t msl_wait_since_pause = 0; + + for (int i = 0; i < n_heaps; i++) + { + gc_heap* hp = g_heaps[i]; + + msl_wait_since_pause += hp->more_space_lock_soh.msl_wait_time; + hp->more_space_lock_soh.msl_wait_time = 0; + + msl_wait_since_pause += hp->more_space_lock_uoh.msl_wait_time; + hp->more_space_lock_uoh.msl_wait_time = 0; + } + + return msl_wait_since_pause; +} #endif //DYNAMIC_HEAP_COUNT #endif //USE_REGIONS @@ -32805,17 +33123,17 @@ void gc_heap::plan_phase (int condemned_gen_number) } else { - dprintf (2, ("gen2 didn't grow (end seg alloc: %zd, , condemned alloc: %zd, gen1 c alloc: %zd", + dprintf (1, ("gen2 didn't grow (end seg alloc: %zd, , condemned alloc: %zd, gen1 c alloc: %zd", end_seg_allocated, condemned_allocated, generation_condemned_allocated (generation_of (max_generation - 1)))); } - dprintf (1, ("older gen's free alloc: %zd->%zd, seg alloc: %zd->%zd, condemned alloc: %zd->%zd", + dprintf (2, ("older gen's free alloc: %zd->%zd, seg alloc: %zd->%zd, condemned alloc: %zd->%zd", r_older_gen_free_list_allocated, generation_free_list_allocated (older_gen), r_older_gen_end_seg_allocated, generation_end_seg_allocated (older_gen), r_older_gen_condemned_allocated, generation_condemned_allocated (older_gen))); - dprintf (1, ("this GC did %zd free list alloc(%zd bytes free space rejected)", + dprintf (2, ("this GC did %zd free list alloc(%zd bytes free space rejected)", free_list_allocated, rejected_free_space)); maxgen_size_increase* maxgen_size_info = &(get_gc_data_per_heap()->maxgen_size_info); @@ -38908,9 +39226,9 @@ void gc_heap::bgc_thread_function() { // this is the case where we have more background GC threads than heaps // - wait until we're told to continue... - dprintf (3, ("BGC thread %d idle", heap_number)); - gc_idle_thread_event.Wait(INFINITE, FALSE); - dprintf (3, ("BGC thread %d waking from idle", heap_number)); + dprintf (9999, ("BGC thread %d idle (%d heaps) (gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); + bgc_idle_thread_event.Wait(INFINITE, FALSE); + dprintf (9999, ("BGC thread %d waking from idle (%d heaps) (gc%Id)", heap_number, n_heaps, VolatileLoadWithoutBarrier (&settings.gc_index))); continue; } #endif //DYNAMIC_HEAP_COUNT @@ -38982,7 +39300,7 @@ void gc_heap::bgc_thread_function() dprintf (SPINLOCK_LOG, ("bgc Lgc")); leave_spin_lock (&gc_lock); #ifdef MULTIPLE_HEAPS - dprintf(1, ("End of BGC - starting all BGC threads")); + dprintf(1, ("End of BGC")); bgc_t_join.restart(); #endif //MULTIPLE_HEAPS } @@ -42859,6 +43177,9 @@ bool gc_heap::init_dynamic_data() { process_start_time = now; smoothed_desired_total[0] = dynamic_data_of (0)->min_size * n_heaps; +#ifdef DYNAMIC_HEAP_COUNT + last_suspended_end_time = now; +#endif //DYNAMIC_HEAP_COUNT #ifdef HEAP_BALANCE_INSTRUMENTATION last_gc_end_time_us = now; dprintf (HEAP_BALANCE_LOG, ("qpf=%zd, start: %zd(%d)", qpf, start_raw_ts, now)); @@ -47957,6 +48278,7 @@ HRESULT GCHeap::Initialize() uint32_t nhp = 1; uint32_t nhp_from_config = 0; + uint32_t max_nhp_from_config = (uint32_t)GCConfig::GetMaxHeapCount(); #ifndef MULTIPLE_HEAPS GCConfig::SetServerGC(false); @@ -48151,6 +48473,10 @@ HRESULT GCHeap::Initialize() #ifdef MULTIPLE_HEAPS assert (nhp <= g_num_processors); + if (max_nhp_from_config) + { + nhp = min (nhp, max_nhp_from_config); + } gc_heap::n_max_heaps = nhp; gc_heap::n_heaps = nhp; hr = gc_heap::initialize_gc (seg_size, large_seg_size, pin_seg_size, nhp); @@ -48301,9 +48627,32 @@ HRESULT GCHeap::Initialize() { // start with only 1 heap gc_heap::smoothed_desired_total[0] /= gc_heap::n_heaps; - gc_heap::g_heaps[0]->change_heap_count (1); + int initial_n_heaps = 1; + dprintf (9999, ("gc_heap::n_heaps is %d, initial %d", gc_heap::n_heaps, initial_n_heaps)); + + { + if (!gc_heap::prepare_to_change_heap_count (initial_n_heaps)) + { + // we don't have sufficient resources. + return E_FAIL; + } + + gc_heap::dynamic_heap_count_data.new_n_heaps = initial_n_heaps; + gc_heap::dynamic_heap_count_data.idle_thread_count = 0; + gc_heap::dynamic_heap_count_data.init_only_p = true; + + int max_threads_to_wake = max (gc_heap::n_heaps, initial_n_heaps); + gc_t_join.update_n_threads (max_threads_to_wake); + gc_heap::gc_start_event.Set (); + } + + gc_heap::g_heaps[0]->change_heap_count (initial_n_heaps); + gc_heap::gc_start_event.Reset (); + + // This needs to be different from our initial heap count so we can make sure we wait for + // the idle threads correctly in gc_thread_function. + gc_heap::dynamic_heap_count_data.last_n_heaps = 0; } - gc_heap::dynamic_heap_count_data.new_n_heaps = gc_heap::n_heaps; #endif //DYNAMIC_HEAP_COUNT GCScan::GcRuntimeStructuresValid (TRUE); @@ -49875,10 +50224,16 @@ void gc_heap::do_post_gc() } #endif //BGC_SERVO_TUNING +#ifdef BACKGROUND_GC + const char* str_gc_type = (settings.concurrent ? "BGC" : (gc_heap::background_running_p () ? "FGC" : "NGC")); +#else + const char* str_gc_type = "NGC"; +#endif //BACKGROUND_GC + dprintf (1, (ThreadStressLog::gcDetailedEndMsg(), - VolatileLoad(&settings.gc_index), - dd_collection_count(hp->dynamic_data_of(0)), - (size_t)(GetHighPrecisionTimeStamp() / 1000), + VolatileLoad (&settings.gc_index), + dd_collection_count (hp->dynamic_data_of (0)), + (size_t)(GetHighPrecisionTimeStamp () / 1000), settings.condemned_generation, (settings.concurrent ? "BGC" : (gc_heap::background_running_p() ? "FGC" : "NGC")), (settings.compaction ? "C" : "S"), diff --git a/src/coreclr/gc/gcconfig.h b/src/coreclr/gc/gcconfig.h index 72786778d5a978..aeded6bc97f17f 100644 --- a/src/coreclr/gc/gcconfig.h +++ b/src/coreclr/gc/gcconfig.h @@ -83,6 +83,7 @@ class GCConfigStringHolder INT_CONFIG (BGCSpinCount, "BGCSpinCount", NULL, 140, "Specifies the bgc spin count") \ INT_CONFIG (BGCSpin, "BGCSpin", NULL, 2, "Specifies the bgc spin time") \ INT_CONFIG (HeapCount, "GCHeapCount", "System.GC.HeapCount", 0, "Specifies the number of server GC heaps") \ + INT_CONFIG (MaxHeapCount, "GCMaxHeapCount", "System.GC.MaxHeapCount", 0, "Specifies the max number of server GC heaps to adjust to") \ INT_CONFIG (Gen0Size, "GCgen0size", NULL, 0, "Specifies the smallest gen0 budget") \ INT_CONFIG (SegmentSize, "GCSegmentSize", NULL, 0, "Specifies the managed heap segment size") \ INT_CONFIG (LatencyMode, "GCLatencyMode", NULL, -1, "Specifies the GC latency mode - batch, interactive or low latency (note that the same " \ diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 1a73add83b429f..cce6c5ee28adf0 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -402,8 +402,6 @@ struct GCDebugSpinLock { #if defined(DYNAMIC_HEAP_COUNT) // time in microseconds we wait for the more space lock uint64_t msl_wait_time; - // number of times we wait for the more space lock - uint64_t msl_wait_count; #endif //DYNAMIC_HEAP_COUNT GCDebugSpinLock() @@ -415,7 +413,7 @@ struct GCDebugSpinLock { , num_switch_thread(0), num_wait_longer(0), num_switch_thread_w(0), num_disable_preemptive_w(0) #endif #if defined(DYNAMIC_HEAP_COUNT) - , msl_wait_time(0), msl_wait_count(0) + , msl_wait_time(0) #endif //DYNAMIC_HEAP_COUNT { } @@ -1148,15 +1146,12 @@ class dynamic_data // // The following 3 fields are updated at the beginning of each GC, if that GC condemns this generation. // - // The number of GC that condemned this generation. The only difference between this - // and collection_count is just that collection_count is maintained for all physical generations - // (currently there are 5) whereas this is only updated for logical generations (there are 3). - size_t gc_clock; - uint64_t time_clock; //time when this gc started + size_t gc_clock; // the gc index + uint64_t time_clock; // time when this gc started uint64_t previous_time_clock; // time when previous gc started // Updated at the end of a GC, if that GC condemns this generation. - size_t gc_elapsed_time; // Time it took for the gc to complete + size_t gc_elapsed_time; // time it took for the gc to complete // // The following fields (and fields in sdata) are initialized during GC init time and do not change. @@ -1495,6 +1490,8 @@ class mark_queue_t void verify_empty(); }; +float median_of_3 (float a, float b, float c); + //class definition of the internal class class gc_heap { @@ -2422,6 +2419,7 @@ class gc_heap #ifndef USE_REGIONS PER_HEAP_METHOD void rearrange_heap_segments(BOOL compacting); #endif //!USE_REGIONS + PER_HEAP_METHOD void delay_free_segments(); PER_HEAP_ISOLATED_METHOD void distribute_free_regions(); #ifdef BACKGROUND_GC PER_HEAP_ISOLATED_METHOD void reset_write_watch_for_gc_heap(void* base_address, size_t region_size); @@ -2597,11 +2595,17 @@ class gc_heap // re-initialize a heap in preparation to putting it back into service PER_HEAP_METHOD void recommission_heap(); + PER_HEAP_ISOLATED_METHOD size_t get_num_completed_gcs(); + + PER_HEAP_ISOLATED_METHOD int calculate_new_heap_count(); + // check if we should change the heap count PER_HEAP_METHOD void check_heap_count(); - PER_HEAP_METHOD bool prepare_to_change_heap_count (int new_n_heaps); + PER_HEAP_ISOLATED_METHOD bool prepare_to_change_heap_count (int new_n_heaps); PER_HEAP_METHOD bool change_heap_count (int new_n_heaps); + + PER_HEAP_ISOLATED_METHOD size_t get_msl_wait_time(); #endif //DYNAMIC_HEAP_COUNT #endif //USE_REGIONS @@ -3778,6 +3782,13 @@ class gc_heap PER_HEAP_FIELD_MAINTAINED mark* loh_pinned_queue; #endif //FEATURE_LOH_COMPACTION +#ifdef DYNAMIC_HEAP_COUNT + PER_HEAP_FIELD_MAINTAINED GCEvent gc_idle_thread_event; +#ifdef BACKGROUND_GC + PER_HEAP_FIELD_MAINTAINED GCEvent bgc_idle_thread_event; +#endif //BACKGROUND_GC +#endif //DYNAMIC_HEAP_COUNT + /******************************************/ // PER_HEAP_FIELD_MAINTAINED_ALLOC fields // /******************************************/ @@ -4084,7 +4095,6 @@ class gc_heap // These 2 fields' values do not change but are set/unset per GC PER_HEAP_ISOLATED_FIELD_SINGLE_GC GCEvent gc_start_event; PER_HEAP_ISOLATED_FIELD_SINGLE_GC GCEvent ee_suspend_event; - PER_HEAP_ISOLATED_FIELD_SINGLE_GC GCEvent gc_idle_thread_event; // Also updated on the heap#0 GC thread because that's where we are actually doing the decommit. PER_HEAP_ISOLATED_FIELD_SINGLE_GC BOOL gradual_decommit_in_progress_p; @@ -4163,6 +4173,10 @@ class gc_heap PER_HEAP_ISOLATED_FIELD_SINGLE_GC uint8_t* gc_high; // high end of the highest region being condemned #endif //USE_REGIONS +#ifdef STRESS_DYNAMIC_HEAP_COUNT + PER_HEAP_ISOLATED_FIELD_SINGLE_GC int heaps_in_this_gc; +#endif //STRESS_DYNAMIC_HEAP_COUNT + /**************************************************/ // PER_HEAP_ISOLATED_FIELD_SINGLE_GC_ALLOC fields // /**************************************************/ @@ -4261,37 +4275,65 @@ class gc_heap #endif //USE_REGIONS #ifdef DYNAMIC_HEAP_COUNT + // Sample collection - + // + // For every GC, we collect the msl wait time + GC pause duration info and use both to calculate the + // throughput cost percentage. We will also be using the wait time and the GC pause duration separately + // for other purposes in the future. + // + // For all gen2 GCs we also keep a separate array currently just for the GC cost. This serves as a backstop + // to smooth out the situation when we rarely pick the gen2 GCs in the first array. struct dynamic_heap_count_data_t { static const int sample_size = 3; struct sample { - uint64_t elapsed_between_gcs; // time between gcs in microseconds - uint64_t gc_elapsed_time; // time the gc took - uint64_t soh_msl_wait_time; // time the allocator spent waiting for the soh msl lock - uint64_t uoh_msl_wait_time; // time the allocator spent waiting for the uoh msl lock - size_t allocating_thread_count;// number of allocating threads - size_t heap_size; + uint64_t elapsed_between_gcs; // time between gcs in microseconds (this should really be between_pauses) + uint64_t gc_pause_time; // pause time for this GC + uint64_t msl_wait_time; }; - unsigned sample_index; + uint32_t sample_index; sample samples[sample_size]; + size_t prev_num_completed_gcs; + + uint32_t gen2_sample_index; + // This is (gc_elapsed_time / time inbetween this and the last gen2 GC) + float gen2_gc_percents[sample_size]; - float median_percent_overhead; // estimated overhead of allocator + gc - float smoothed_median_percent_overhead; // exponentially smoothed version - float percent_heap_space_cost_per_heap; // percent space cost of adding a heap - float overhead_reduction_per_step_up; // percentage effect on overhead of increasing heap count - float overhead_increase_per_step_down; // percentage effect on overhead of decreasing heap count - float space_cost_increase_per_step_up; // percentage effect on space of increasing heap count - float space_cost_decrease_per_step_down;// percentage effect on space of decreasing heap count + float median_throughput_cost_percent; // estimated overhead of allocator + gc + float smoothed_median_throughput_cost_percent; // exponentially smoothed version + float percent_heap_space_cost_per_heap; // percent space cost of adding a heap + float tcp_reduction_per_step_up; // throughput cost percent effect of increasing heap count + float tcp_increase_per_step_down; // throughput cost percent effect of decreasing heap count + float scp_increase_per_step_up; // space cost percent effect of increasing heap count + float scp_decrease_per_step_down; // space cost percent effect of decreasing heap count int new_n_heaps; + // the heap count we changed from + int last_n_heaps; + // don't start a GC till we see (n_max_heaps - new_n_heaps) number of threads idling + VOLATILE(int32_t) idle_thread_count; + bool init_only_p; + + bool should_change_heap_count; + int heap_count_to_change_to; + int heap_count_change_count; #ifdef STRESS_DYNAMIC_HEAP_COUNT int lowest_heap_with_msl_uoh; #endif //STRESS_DYNAMIC_HEAP_COUNT + + float get_median_gen2_gc_percent() + { + return median_of_3 (gen2_gc_percents[0], gen2_gc_percents[1], gen2_gc_percents[2]); + } }; PER_HEAP_ISOLATED_FIELD_MAINTAINED dynamic_heap_count_data_t dynamic_heap_count_data; + PER_HEAP_ISOLATED_FIELD_MAINTAINED uint64_t last_suspended_end_time; + // If the last full GC is blocking, this is that GC's index; for BGC, this is the settings.gc_index + // when the BGC ended. + PER_HEAP_ISOLATED_FIELD_MAINTAINED size_t gc_index_full_gc_end; #endif //DYNAMIC_HEAP_COUNT /****************************************************/ @@ -4867,7 +4909,6 @@ uint64_t& dd_previous_time_clock (dynamic_data* inst) return inst->previous_time_clock; } - inline size_t& dd_gc_clock_interval (dynamic_data* inst) { From 18bfe59bc967529e633498ad20c9710a5e4752d0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 09:26:56 -0700 Subject: [PATCH 287/345] Update dependencies from https://github.com/dotnet/emsdk build 20230919.4 (#92322) Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.2.23469.1 -> To Version 8.0.0-rc.2.23469.4 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 489044e0d17884..bb8f1d633fbb01 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,9 +90,9 @@ 89be445dd4936157533ad96bafb95f701430653a - + https://github.com/dotnet/emsdk - ca3e8e40f417e421141638c66dd301395afee66d + ea0e8e8214e9acc0cba7e78a836ed6656f788d11 diff --git a/eng/Versions.props b/eng/Versions.props index d56eeab17ef17d..61344b9a916136 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.2.23469.1 + 8.0.0-rc.2.23469.4 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From 49bf70a429a6122217f2c88e778ce8115ceac3bd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 09:30:17 -0700 Subject: [PATCH 288/345] Update dependencies from https://github.com/dotnet/source-build-externals build 20230919.1 (#92340) Microsoft.SourceBuild.Intermediate.source-build-externals From Version 8.0.0-alpha.1.23468.1 -> To Version 8.0.0-alpha.1.23469.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 04567c6742f81f..951d1ef1c05f97 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -100,9 +100,9 @@ d825c6693d4e26f63aaa93c3c1d057faa098e347 - + https://github.com/dotnet/source-build-externals - e9d6489787a5ea5400a31dfa34aa6ad6b590de9b + c42a7ce3b6fa02957e7b4ef995c5c2a9a23d294c From f52a29561c30ccd7475e40a4fb56928738a6eac2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:19:28 -0700 Subject: [PATCH 289/345] [release/8.0-rc1] [release/8.0] Fix wasi build. (#92368) * Fix wasi build. * dummy change in wasi README to trigger a build * dummy change in wasi to trigger a build --------- Co-authored-by: Zoltan Varga Co-authored-by: Ankit Jain --- eng/pipelines/common/templates/pipeline-with-resources.yml | 4 ++-- src/mono/wasi/README.md | 3 ++- src/mono/wasi/build/WasiApp.targets | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index c30ce8597808d8..02242394fba671 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -85,12 +85,12 @@ resources: image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8 - container: browser_wasm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly-20230913040940-1edc1c6 env: ROOTFS_DIR: /crossrootfs/x64 - container: wasi_wasm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-webassembly-20230913040940-1edc1c6 env: ROOTFS_DIR: /crossrootfs/x64 diff --git a/src/mono/wasi/README.md b/src/mono/wasi/README.md index 66e59384297bb3..4c8759006359da 100644 --- a/src/mono/wasi/README.md +++ b/src/mono/wasi/README.md @@ -17,6 +17,7 @@ or for just native rebuild ./build.sh -bl -os wasi -subset mono.runtime+libs.native+mono.wasiruntime -c Debug ``` + ### 3. Run it Finally, you can build and run the sample: @@ -49,4 +50,4 @@ Download the Mono Debug extension and configure a launch.json like this: } ] } -``` \ No newline at end of file +``` diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index 1b8fc4e3fa9333..099ba8c3ebea27 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -4,8 +4,6 @@ - 8.0.100-rc.1.23415.5 1.1.2-beta1.23323.1 8.0.0-preview-20230918.1 @@ -257,5 +255,8 @@ 3.1.7 1.0.406601 + + 8.0.100-rc.2.23470.7 + $(MicrosoftDotnetSdkInternalVersion) diff --git a/src/mono/wasm/README.md b/src/mono/wasm/README.md index 34c18bc8711468..cdace086f5603e 100644 --- a/src/mono/wasm/README.md +++ b/src/mono/wasm/README.md @@ -350,3 +350,12 @@ npm update --lockfile-version=1 | Multi-thread | linux: build only | none | * `high resource aot` runs a few specific library tests with AOT, that require more memory to AOT. + + +# Perf pipeline + +TBD + +## Updates needed + +- when the base OS is upgraded, check if the version of node installed in the `eng/pipelines/coreclr/templates/run-performance-job.yml` needs an upgrade too. diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs index 10717b334174b9..b006bf7a93e5c3 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests3.cs @@ -63,7 +63,7 @@ public static class MyDllImports public static extern int cpp_add(int a, int b); }}"; - File.WriteAllText(Path.Combine(_projectDir!, "Pages", "MyDllImport.cs"), myDllImportCs); + File.WriteAllText(Path.Combine(_projectDir!, "Components", "Pages", "MyDllImport.cs"), myDllImportCs); AddItemsPropertiesToProject(projectFile, extraItems: @""); BlazorAddRazorButton("cpp_add", """ @@ -144,7 +144,7 @@ public void BugRegression_60479_WithRazorClassLib() Assert.Contains(razorClassLibraryFileName, lazyVal.EnumerateObject().Select(jp => jp.Name)); } - private void BlazorAddRazorButton(string buttonText, string customCode, string methodName = "test", string razorPage = "Pages/Counter.razor") + private void BlazorAddRazorButton(string buttonText, string customCode, string methodName = "test", string razorPage = "Components/Pages/Counter.razor") { string additionalCode = $$"""

Output: @outputText

diff --git a/src/mono/wasm/Wasm.Build.Tests/Blazor/WorkloadRequiredTests.cs b/src/mono/wasm/Wasm.Build.Tests/Blazor/WorkloadRequiredTests.cs index cbe3e461ec9cde..7ca663dce5372f 100644 --- a/src/mono/wasm/Wasm.Build.Tests/Blazor/WorkloadRequiredTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/Blazor/WorkloadRequiredTests.cs @@ -84,7 +84,7 @@ public async Task WorkloadNotRequiredForInvariantGlobalization(string config, bo if (invariant) AddItemsPropertiesToProject(projectFile, extraProperties: "true"); - string counterPath = Path.Combine(Path.GetDirectoryName(projectFile)!, "Pages", "Counter.razor"); + string counterPath = Path.Combine(Path.GetDirectoryName(projectFile)!, "Components", "Pages", "Counter.razor"); string allText = File.ReadAllText(counterPath); string ccText = "currentCount++;"; if (allText.IndexOf(ccText) < 0) diff --git a/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs b/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs index e520057d5b3bdf..224527142fa898 100644 --- a/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs +++ b/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs @@ -215,7 +215,7 @@ private bool InstallPacks(InstallWorkloadRequest req, string nugetConfigContents (int exitCode, string output) = Utils.TryRunProcess( Log, Path.Combine(req.TargetPath, "dotnet"), - $"workload install --skip-manifest-update --configfile \"{nugetConfigPath}\" --temp-dir \"{_tempDir}/workload-install-temp\" {req.WorkloadId}", + $"workload install --skip-manifest-update --skip-sign-check --configfile \"{nugetConfigPath}\" --temp-dir \"{_tempDir}/workload-install-temp\" {req.WorkloadId}", workingDir: _tempDir, envVars: new Dictionary () { ["NUGET_PACKAGES"] = _nugetCachePath From 1361b189a45e312958e3f8509f053150300b494f Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 20 Sep 2023 19:15:45 -0400 Subject: [PATCH 291/345] Update dependencies from dotnet/emsdk Picking the update from https://github.com/dotnet/runtime/pull/92320 to here, to avoid the overlap. --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9bedd07535a17d..f33ad2fde34080 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,9 +90,9 @@ 89be445dd4936157533ad96bafb95f701430653a
- + https://github.com/dotnet/emsdk - ea0e8e8214e9acc0cba7e78a836ed6656f788d11 + 446eeb331fcbf2f48c14a377601a8ab950ec942e diff --git a/eng/Versions.props b/eng/Versions.props index abf8964b954d1c..a8dc199cc94ed3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -238,7 +238,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.2.23469.4 + 8.0.0-rtm.23470.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From 02d408eeb7e74d6cbc58807eb5c418180e6b6909 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 20 Sep 2023 16:41:07 -0400 Subject: [PATCH 292/345] [wasm] InstallWorkloadFromArtifacts: correctly handle rtm versions In case of a version like `8.0.100-rtm.23470.1`, we incorrectly extracted `-rtm.23470` instead of `-rtm`, which resulted in trying to install package named `Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100-rtm.23470` instead of `Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100-rtm`. --- src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs b/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs index 224527142fa898..62817719af0a14 100644 --- a/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs +++ b/src/tasks/WorkloadBuildTasks/InstallWorkloadFromArtifacts.cs @@ -49,7 +49,7 @@ public partial class InstallWorkloadFromArtifacts : Task private string _tempDir = string.Empty; private string _nugetCachePath = string.Empty; - [GeneratedRegex(@"^\d+\.\d+\.\d+(-[A-z]*\.*\d*)?")] + [GeneratedRegex(@"^\d+\.\d+\.\d+(-rtm|-[A-z]*\.*\d*)?")] private static partial Regex bandVersionRegex(); public override bool Execute() From c4ea964c38a09a86871d9ad19deefe5fb5070315 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 02:24:03 -0700 Subject: [PATCH 293/345] Add missing case for constrained gsharedvt call. (#92347) https://github.com/dotnet/runtime/commit/1b788f4dc3e3a8829488e52c032ad6a70671e070 added a new value to our MonoRgctxInfoType enum type, but appears that all cases where not full adjusted. Running System.Buffers tests in full AOT hits the assert in info_equal about missing case, https://github.com/dotnet/runtime/blob/0dc5903679606b072adac70a268cdb77d1147b3e/src/mono/mono/mini/mini-generic-sharing.c#L2908. This commit adds the new enum value and align handling similar to other cases added by that commit. Co-authored-by: lateralusX --- src/mono/mono/mini/mini-generic-sharing.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/mini-generic-sharing.c b/src/mono/mono/mini/mini-generic-sharing.c index 6ad8dcb0075cfc..c131d51a6bd070 100644 --- a/src/mono/mono/mini/mini-generic-sharing.c +++ b/src/mono/mono/mini/mini-generic-sharing.c @@ -2886,7 +2886,8 @@ info_equal (gpointer data1, gpointer data2, MonoRgctxInfoType info_type) return data1 == data2; case MONO_RGCTX_INFO_VIRT_METHOD: case MONO_RGCTX_INFO_VIRT_METHOD_CODE: - case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: { + case MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE: + case MONO_RGCTX_INFO_GSHAREDVT_CONSTRAINED_CALL_INFO: { MonoJumpInfoVirtMethod *info1 = (MonoJumpInfoVirtMethod *)data1; MonoJumpInfoVirtMethod *info2 = (MonoJumpInfoVirtMethod *)data2; From 8ae598eed28b27cb15c75abf61c7abf0fdd9f367 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 02:24:45 -0700 Subject: [PATCH 294/345] [release/8.0-rc2] Fixes for LLVM AOT on Windows from @lateralusX (#92365) * Fixes for LLVM AOT on Windows from @lateralusX * fix HOST/TARGET issue --------- Co-authored-by: Jo Shields --- src/mono/mono/mini/aot-compiler.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index e067d2714d8a37..c342ef5d007571 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -10708,6 +10708,18 @@ execute_system (const char * command) #ifdef ENABLE_LLVM +#ifdef HOST_WIN32 +#define OPT_NAME "opt.exe" +#else +#define OPT_NAME "opt" +#endif + +#ifdef HOST_WIN32 +#define LLC_NAME "llc.exe" +#else +#define LLC_NAME "llc" +#endif + /* * emit_llvm_file: * @@ -10776,11 +10788,11 @@ emit_llvm_file (MonoAotCompile *acfg) } else { #if LLVM_API_VERSION >= 1600 /* The safepoints pass requires new pass manager syntax*/ - opts = g_strdup ("-disable-tail-calls -passes='"); + opts = g_strdup ("-disable-tail-calls -passes=\""); if (!acfg->aot_opts.llvm_only) { opts = g_strdup_printf ("%sdefault,", opts); } - opts = g_strdup_printf ("%splace-safepoints' -spp-all-backedges", opts); + opts = g_strdup_printf ("%splace-safepoints\" -spp-all-backedges", opts); #elif LLVM_API_VERSION >= 1300 /* The safepoints pass requires the old pass manager */ opts = g_strdup ("-disable-tail-calls -place-safepoints -spp-all-backedges -enable-new-pm=0"); @@ -10810,7 +10822,7 @@ emit_llvm_file (MonoAotCompile *acfg) opts = g_strdup_printf ("%s -fp-contract=fast -enable-no-infs-fp-math -enable-no-nans-fp-math -enable-no-signed-zeros-fp-math -enable-no-trapping-fp-math -enable-unsafe-fp-math", opts); } - command = g_strdup_printf ("\"%sopt\" -f %s -o \"%s\" \"%s\"", acfg->aot_opts.llvm_path, opts, optbc, tempbc); + command = g_strdup_printf ("\"%s" OPT_NAME "\" -f %s -o \"%s\" \"%s\"", acfg->aot_opts.llvm_path, opts, optbc, tempbc); aot_printf (acfg, "Executing opt: %s\n", command); if (execute_system (command) != 0) return FALSE; @@ -10885,7 +10897,7 @@ emit_llvm_file (MonoAotCompile *acfg) g_string_append_printf (acfg->llc_args, " -mattr=%s", acfg->aot_opts.llvm_cpu_attr); } - command = g_strdup_printf ("\"%sllc\" %s -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, output_fname, acfg->tmpbasename); + command = g_strdup_printf ("\"%s" LLC_NAME "\" %s -o \"%s\" \"%s.opt.bc\"", acfg->aot_opts.llvm_path, acfg->llc_args->str, output_fname, acfg->tmpbasename); g_free (output_fname); aot_printf (acfg, "Executing llc: %s\n", command); From 1757497f37245d1756870fb1c0b3221c0d235d54 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 02:25:17 -0700 Subject: [PATCH 295/345] [release/8.0] Properly handle debugger-enumerating interior pointers and enregistered refs (#92360) * Fix issue with enregistered values * Fix assert and enregistered ref reporting * Fix issue from merge --------- Co-authored-by: Lee Culver Co-authored-by: Juan Sebastian Hoyos Ayala Co-authored-by: Juan Hoyos <19413848+hoyosjs@users.noreply.github.com> --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 3 ++- src/coreclr/debug/di/rsclass.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 67d5b1e60d948c..07208001b0c3b8 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -7788,8 +7788,9 @@ HRESULT DacStackReferenceWalker::Next(ULONG count, DacGcReference stackRefs[], U stackRefs[i].i64ExtraData = 0; const SOSStackRefData &sosStackRef = mList.Get(i); - if (sosStackRef.Flags & GC_CALL_INTERIOR) + if (sosStackRef.Flags & GC_CALL_INTERIOR || sosStackRef.Address == 0) { + // Direct pointer case - interior pointer, Frame ref, or enregistered var. stackRefs[i].pObject = CLRDATA_ADDRESS_TO_TADDR(sosStackRef.Object) | 1; } else diff --git a/src/coreclr/debug/di/rsclass.cpp b/src/coreclr/debug/di/rsclass.cpp index ec52823c07af5f..55f83b48a6d211 100644 --- a/src/coreclr/debug/di/rsclass.cpp +++ b/src/coreclr/debug/di/rsclass.cpp @@ -132,6 +132,7 @@ HRESULT CordbClass::GetStaticFieldValue(mdFieldDef fieldDef, IMetaDataImport * pImport = NULL; EX_TRY { + RSLockHolder lockHolder(GetProcess()->GetProcessLock()); pImport = GetModule()->GetMetaDataImporter(); // throws // Validate the token. @@ -1191,4 +1192,3 @@ HRESULT CordbClass::SearchFieldInfo( // Well, the field doesn't even belong to this class... ThrowHR(E_INVALIDARG); } - From 12fc9044307e32e143eb7cbaf1d68badf61b192c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 08:35:35 -0700 Subject: [PATCH 296/345] Fix the VN for xor operation (#92372) Co-authored-by: Kunal Pathak --- src/coreclr/jit/valuenum.cpp | 2 +- .../JitBlue/Runtime_91252/Runtime_91252.cs | 37 +++++++++++++++++++ .../Runtime_91252/Runtime_91252.csproj | 8 ++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.csproj diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 2ea2ee7845b8b2..2c638535d786e4 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -7891,7 +7891,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary(var_types type, #endif { // Handle `x ^ x == 0` - return arg0VN; + return VNZeroForType(type); } default: diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.cs b/src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.cs new file mode 100644 index 00000000000000..d4035f3de978fc --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// +// This test verifies if we correctly value number the operation of +// x ^ x to zero. +// +// Found by Antigen + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public class Issue_91252 +{ + static Vector64 s_v64_int_22 = Vector64.Create(-5); + Vector64 v64_int_72 = Vector64.Create(-1); + + [MethodImpl(MethodImplOptions.NoInlining)] + public int Repro() + { + s_v64_int_22 = v64_int_72; + return Check(v64_int_72 ^ v64_int_72); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public int Check(Vector64 a) + { + return (a == Vector64.Zero) ? 100 : 101; + } + + [Fact] + public static int EntryPoint() + { + var obj = new Issue_91252(); + return obj.Repro(); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_91252/Runtime_91252.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 76252f33738dc02f5015510c5ebc52280a0c448b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 09:34:09 -0700 Subject: [PATCH 297/345] [release/8.0] Update dependencies from dotnet/roslyn (#92303) * Update dependencies from https://github.com/dotnet/roslyn build 20230919.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230919.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230919.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230919.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230919.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.9 * Update dependencies from https://github.com/dotnet/roslyn build 20230919.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230919.11 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23469.11 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230920.12 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23470.12 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23471.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23469.1 -> To Version 4.8.0-3.23471.2 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f12a5b894116f2..e40acd650b02cb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 9233e36abc5e2ca263dbd4d1616f35623440a935 + 9f6f97debe7fe8121a2249f807343d12ef1e4ac6 - + https://github.com/dotnet/roslyn - 9233e36abc5e2ca263dbd4d1616f35623440a935 + 9f6f97debe7fe8121a2249f807343d12ef1e4ac6 - + https://github.com/dotnet/roslyn - 9233e36abc5e2ca263dbd4d1616f35623440a935 + 9f6f97debe7fe8121a2249f807343d12ef1e4ac6 https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index a8dc199cc94ed3..566506f35543b1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -42,9 +42,9 @@ 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. --> - 4.8.0-3.23469.1 - 4.8.0-3.23469.1 - 4.8.0-3.23469.1 + 4.8.0-3.23471.2 + 4.8.0-3.23471.2 + 4.8.0-3.23471.2 false release - -$(PreReleaseVersionLabel).$(PreReleaseVersionIteration) + -$(PreReleaseVersionLabel) + -$(PreReleaseVersionLabel).$(PreReleaseVersionIteration) $(SdkBandVersion)$(WorkloadVersionSuffix) false From d365be87223a7b3575f45b4abac30e742a4619fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 15:37:09 -0700 Subject: [PATCH 300/345] JIT: Fix invalid containment of vector broadcasts (#92371) The containment checks for vector broadcasts were missing a size check, meaning that a uint broadcast could contain a ubyte/ushort indirection. That would lead to out-of-bounds reads. Fix #83387 Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/gentree.cpp | 4 ++-- src/coreclr/jit/lowerxarch.cpp | 3 +++ .../JitBlue/Runtime_83387/Runtime_83387.cs | 19 +++++++++++++++++++ .../Runtime_83387/Runtime_83387.csproj | 8 ++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.csproj diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index a30c3794efdd29..d6d524f375ea73 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -19639,8 +19639,8 @@ GenTree* Compiler::gtNewSimdBinOpNode( } else { - assert(op2->TypeIs(type, simdBaseType, genActualType(simdBaseType)) || - (op2->TypeIs(TYP_SIMD12) && type == TYP_SIMD16)); + assert((genActualType(op2) == genActualType(type)) || (genActualType(op2) == genActualType(simdBaseType)) || + (op2->TypeIs(TYP_SIMD12) && (type == TYP_SIMD16))); } NamedIntrinsic intrinsic = NI_Illegal; diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index d1c3e317d83b87..30c2a832b94fc1 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -7956,6 +7956,9 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre // The memory form of this already takes a pointer and should be treated like a MemoryLoad supportsGeneralLoads = !childNode->OperIsHWIntrinsic(); } + + supportsGeneralLoads = + supportsGeneralLoads && (genTypeSize(childNode) >= genTypeSize(parentNode->GetSimdBaseType())); break; } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.cs b/src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.cs new file mode 100644 index 00000000000000..cb70acd1677573 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public class Runtime_83387 +{ + [MethodImpl(MethodImplOptions.NoOptimization)] + [Fact] + public static int TestEntryPoint() + { + (ushort A, ushort R) c = (1, 65535); + Vector128 v1 = Vector128.Create((uint)100); + v1 = v1 * c.A; + return (int)v1.ToScalar(); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_83387/Runtime_83387.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From 79bd0070701302c28aa820376c0b029d15f51ac0 Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Thu, 21 Sep 2023 15:37:35 -0700 Subject: [PATCH 301/345] [release/8.0-rc2] Bump downlevel version to 7.0.12 (#92419) Co-authored-by: Steve Pfister --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index abf8964b954d1c..a7d36117e12b76 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -7,7 +7,7 @@ 0 0 8.0.100 - 7.0.11 + 7.0.12 6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11)) rc 2 From b1dbbb964a4daba07fe13c4150133f1d5d41ceb0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:54:40 -0700 Subject: [PATCH 302/345] [release/8.0-rc2] [browser] Fix SIMD+EH check (#92439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move simd+eh check after emcripten provided build time values * Call cwraps.mono_wasm_abort from runtimeHelpers.abort when cwraps are ready (onRuntimeInitializedAsync) * Assign early mono_wasm_exit and abort even earlier * Fire feature check before awaiting wasm download, but await it after. * Whitespaces --------- Co-authored-by: Marek Fišera --- src/mono/wasm/runtime/globals.ts | 6 +++++ src/mono/wasm/runtime/startup.ts | 38 ++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/mono/wasm/runtime/globals.ts b/src/mono/wasm/runtime/globals.ts index 66948642bbc55c..88be75543ab4e5 100644 --- a/src/mono/wasm/runtime/globals.ts +++ b/src/mono/wasm/runtime/globals.ts @@ -66,6 +66,12 @@ export function setRuntimeGlobals(globalObjects: GlobalObjects) { beforeOnRuntimeInitialized: createPromiseController(), afterOnRuntimeInitialized: createPromiseController(), afterPostRun: createPromiseController(), + mono_wasm_exit: () => { + throw new Error("Mono shutdown"); + }, + abort: (reason: any) => { + throw reason; + } }); Object.assign(globalObjects.module.config!, {}) as any; diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index e6f8d80ef82f48..d8eab74d8b2500 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -40,15 +40,7 @@ import { assertNoProxies } from "./gc-handles"; const MONO_PTHREAD_POOL_SIZE = 4; export async function configureRuntimeStartup(): Promise { - if (linkerWasmEnableSIMD) { - mono_assert(await loaderHelpers.simd(), "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); - } - if (linkerWasmEnableEH) { - mono_assert(await loaderHelpers.exceptions(), "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); - } - await init_polyfills_async(); - await checkMemorySnapshotSize(); } @@ -240,6 +232,15 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { // wait for previous stage await runtimeHelpers.afterPreRun.promise; mono_log_debug("onRuntimeInitialized"); + + runtimeHelpers.mono_wasm_exit = cwraps.mono_wasm_exit; + runtimeHelpers.abort = (reason: any) => { + if (!loaderHelpers.is_exited()) { + cwraps.mono_wasm_abort(); + } + throw reason; + }; + const mark = startMeasure(); // signal this stage, this will allow pending assets to allocate memory runtimeHelpers.beforeOnRuntimeInitialized.promise_control.resolve(); @@ -361,13 +362,6 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void { } init_c_exports(); - runtimeHelpers.mono_wasm_exit = cwraps.mono_wasm_exit; - runtimeHelpers.abort = (reason: any) => { - if (!loaderHelpers.is_exited()) { - cwraps.mono_wasm_abort(); - } - throw reason; - }; cwraps_internal(INTERNAL); if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) { cwraps_mono_api(MONO); @@ -386,7 +380,6 @@ async function mono_wasm_pre_init_essential_async(): Promise { mono_log_debug("mono_wasm_pre_init_essential_async"); Module.addRunDependency("mono_wasm_pre_init_essential_async"); - if (MonoWasmThreads) { preAllocatePThreadWorkerPool(MONO_PTHREAD_POOL_SIZE, runtimeHelpers.config); } @@ -466,8 +459,12 @@ async function instantiate_wasm_module( await runtimeHelpers.beforePreInit.promise; Module.addRunDependency("instantiate_wasm_module"); + const wasmFeaturePromise = ensureUsedWasmFeatures(); + replace_linker_placeholders(imports); const assetToLoad = await loaderHelpers.wasmDownloadPromise.promise; + + await wasmFeaturePromise; await instantiate_wasm_asset(assetToLoad, imports, successCallback); assetToLoad.pendingDownloadInternal = null as any; // GC assetToLoad.pendingDownload = null as any; // GC @@ -499,6 +496,15 @@ async function instantiate_wasm_module( Module.removeRunDependency("instantiate_wasm_module"); } +async function ensureUsedWasmFeatures() { + if (linkerWasmEnableSIMD) { + mono_assert(await loaderHelpers.simd(), "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); + } + if (linkerWasmEnableEH) { + mono_assert(await loaderHelpers.exceptions(), "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features"); + } +} + async function mono_wasm_before_memory_snapshot() { const mark = startMeasure(); if (runtimeHelpers.loadedMemorySnapshotSize) { From 63d0c6454c7f9530140bc7aa9d97790996f21d08 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:58:50 -0700 Subject: [PATCH 303/345] [release/8.0-rc2] Address feedback and fix some TensorPrimitives issues (#92437) * Address feedback and fix some TensorPrimitives issues - Added a few APIs based on initial feedback: Abs (vectorized), Log2, and element-wise Max/Min{Magnitude} - Renamed L2Normalize to Norm - Fixed semantics of Min/MaxMagnitude to return original value rather than the absolute value - Renamed a few helper types for consistency - Added tests * Add a few more uses of Tolerance --------- Co-authored-by: Stephen Toub --- .../ref/System.Numerics.Tensors.cs | 8 +- .../Numerics/Tensors/TensorPrimitives.cs | 147 ++++++++- .../Tensors/TensorPrimitives.netcore.cs | 12 +- .../Tensors/TensorPrimitives.netstandard.cs | 12 +- .../tests/TensorPrimitivesTests.cs | 285 +++++++++++++++--- 5 files changed, 410 insertions(+), 54 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs index 50eaa00160e5cb..99bd4703574e55 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.cs @@ -8,6 +8,7 @@ namespace System.Numerics.Tensors { public static partial class TensorPrimitives { + public static void Abs(System.ReadOnlySpan x, System.Span destination) { } public static void Add(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { } public static void Add(System.ReadOnlySpan x, float y, System.Span destination) { } public static void AddMultiply(System.ReadOnlySpan x, System.ReadOnlySpan y, System.ReadOnlySpan multiplier, System.Span destination) { } @@ -24,12 +25,17 @@ public static void Exp(System.ReadOnlySpan x, System.Span destinat public static int IndexOfMaxMagnitude(System.ReadOnlySpan x) { throw null; } public static int IndexOfMin(System.ReadOnlySpan x) { throw null; } public static int IndexOfMinMagnitude(System.ReadOnlySpan x) { throw null; } - public static float L2Normalize(System.ReadOnlySpan x) { throw null; } + public static float Norm(System.ReadOnlySpan x) { throw null; } public static void Log(System.ReadOnlySpan x, System.Span destination) { } + public static void Log2(System.ReadOnlySpan x, System.Span destination) { } public static float Max(System.ReadOnlySpan x) { throw null; } + public static void Max(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { throw null; } public static float MaxMagnitude(System.ReadOnlySpan x) { throw null; } + public static void MaxMagnitude(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { throw null; } public static float Min(System.ReadOnlySpan x) { throw null; } + public static void Min(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { throw null; } public static float MinMagnitude(System.ReadOnlySpan x) { throw null; } + public static void MinMagnitude(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { throw null; } public static void Multiply(System.ReadOnlySpan x, System.ReadOnlySpan y, System.Span destination) { } public static void Multiply(System.ReadOnlySpan x, float y, System.Span destination) { } public static void MultiplyAdd(System.ReadOnlySpan x, System.ReadOnlySpan y, System.ReadOnlySpan addend, System.Span destination) { } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs index a400095b08ad39..d28d4bacafdb8e 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.cs @@ -93,6 +93,14 @@ public static void Divide(ReadOnlySpan x, float y, Span destinatio public static void Negate(ReadOnlySpan x, Span destination) => InvokeSpanIntoSpan(x, destination); + /// Computes the element-wise result of: MathF.Abs(). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = MathF.Abs([i]). + public static void Abs(ReadOnlySpan x, Span destination) => + InvokeSpanIntoSpan(x, destination); + /// Computes the element-wise result of: ( + ) * . /// The first tensor, represented as a span. /// The second tensor, represented as a span. @@ -200,6 +208,24 @@ public static void Log(ReadOnlySpan x, Span destination) } } + /// Computes the element-wise result of: log2(). + /// The tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Destination is too short. + /// This method effectively does [i] = .Log2([i]). + public static void Log2(ReadOnlySpan x, Span destination) + { + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = Log2(x[i]); + } + } + /// Computes the element-wise result of: cosh(). /// The tensor, represented as a span. /// The destination tensor, represented as a span. @@ -318,9 +344,9 @@ public static float Dot(ReadOnlySpan x, ReadOnlySpan y) // BLAS1: /// /// The first tensor, represented as a span. /// The L2 norm. - public static float L2Normalize(ReadOnlySpan x) // BLAS1: nrm2 + public static float Norm(ReadOnlySpan x) // BLAS1: nrm2 { - return MathF.Sqrt(Aggregate(0f, x)); + return MathF.Sqrt(Aggregate(0f, x)); } /// @@ -345,7 +371,7 @@ public static void SoftMax(ReadOnlySpan x, Span destination) for (int i = 0; i < x.Length; i++) { - expSum += MathF.Pow((float)Math.E, x[i]); + expSum += MathF.Exp(x[i]); } for (int i = 0; i < x.Length; i++) @@ -421,6 +447,31 @@ public static float Max(ReadOnlySpan x) return result; } + /// Computes the element-wise result of: MathF.Max(, ). + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = MathF.Max([i], [i]). + public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span destination) + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Max(x[i], y[i]); + } + } + /// Computes the minimum element in . /// The tensor, represented as a span. /// The minimum element in . @@ -464,6 +515,31 @@ public static float Min(ReadOnlySpan x) return result; } + /// Computes the element-wise result of: MathF.Min(, ). + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = MathF.Min([i], [i]). + public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span destination) + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MathF.Min(x[i], y[i]); + } + } + /// Computes the maximum magnitude of any element in . /// The tensor, represented as a span. /// The maximum magnitude of any element in . @@ -508,7 +584,32 @@ public static float MaxMagnitude(ReadOnlySpan x) } } - return resultMag; + return result; + } + + /// Computes the element-wise result of: MathF.MaxMagnitude(, ). + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = MathF.MaxMagnitude([i], [i]). + public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MaxMagnitude(x[i], y[i]); + } } /// Computes the minimum magnitude of any element in . @@ -522,6 +623,7 @@ public static float MinMagnitude(ReadOnlySpan x) ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); } + float result = float.PositiveInfinity; float resultMag = float.PositiveInfinity; for (int i = 0; i < x.Length; i++) @@ -543,16 +645,43 @@ public static float MinMagnitude(ReadOnlySpan x) if (currentMag < resultMag) { + result = current; resultMag = currentMag; } } else if (IsNegative(current)) { + result = current; resultMag = currentMag; } } - return resultMag; + return result; + } + + /// Computes the element-wise result of: MathF.MinMagnitude(, ). + /// The first tensor, represented as a span. + /// The second tensor, represented as a span. + /// The destination tensor, represented as a span. + /// Length of '' must be same as length of ''. + /// Destination is too short. + /// This method effectively does [i] = MathF.MinMagnitude([i], [i]). + public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) + { + if (x.Length != y.Length) + { + ThrowHelper.ThrowArgument_SpansMustHaveSameLength(); + } + + if (x.Length > destination.Length) + { + ThrowHelper.ThrowArgument_DestinationTooShort(); + } + + for (int i = 0; i < x.Length; i++) + { + destination[i] = MinMagnitude(x[i], y[i]); + } } /// Computes the index of the maximum element in . @@ -744,14 +873,14 @@ public static unsafe int IndexOfMinMagnitude(ReadOnlySpan x) /// The tensor, represented as a span. /// The result of adding all elements in , or zero if is empty. public static float Sum(ReadOnlySpan x) => - Aggregate(0f, x); + Aggregate(0f, x); /// Computes the sum of the squares of every element in . /// The tensor, represented as a span. /// The result of adding every element in multiplied by itself, or zero if is empty. /// This method effectively does .Sum(.Multiply(, )). public static float SumOfSquares(ReadOnlySpan x) => - Aggregate(0f, x); + Aggregate(0f, x); /// Computes the sum of the absolute values of every element in . /// The tensor, represented as a span. @@ -761,7 +890,7 @@ public static float SumOfSquares(ReadOnlySpan x) => /// This method corresponds to the asum method defined by BLAS1. /// public static float SumOfMagnitudes(ReadOnlySpan x) => - Aggregate(0f, x); + Aggregate(0f, x); /// Computes the product of all elements in . /// The tensor, represented as a span. @@ -774,7 +903,7 @@ public static float Product(ReadOnlySpan x) ThrowHelper.ThrowArgument_SpansMustBeNonEmpty(); } - return Aggregate(1.0f, x); + return Aggregate(1.0f, x); } /// Computes the product of the element-wise result of: + . diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs index ae5af404ac1aff..8eb1769d5eaee8 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netcore.cs @@ -51,6 +51,12 @@ public static void ConvertToSingle(ReadOnlySpan source, Span destin private static bool IsNegative(float f) => float.IsNegative(f); + private static float MaxMagnitude(float x, float y) => MathF.MaxMagnitude(x, y); + + private static float MinMagnitude(float x, float y) => MathF.MinMagnitude(x, y); + + private static float Log2(float x) => MathF.Log2(x); + private static float CosineSimilarityCore(ReadOnlySpan x, ReadOnlySpan y) { // Compute the same as: @@ -1184,7 +1190,7 @@ public static float Invoke(Vector512 x) #endif } - private readonly struct LoadIdentity : IUnaryOperator + private readonly struct IdentityOperator : IUnaryOperator { public static float Invoke(float x) => x; public static Vector128 Invoke(Vector128 x) => x; @@ -1194,7 +1200,7 @@ public static float Invoke(Vector512 x) #endif } - private readonly struct LoadSquared : IUnaryOperator + private readonly struct SquaredOperator : IUnaryOperator { public static float Invoke(float x) => x * x; public static Vector128 Invoke(Vector128 x) => x * x; @@ -1204,7 +1210,7 @@ public static float Invoke(Vector512 x) #endif } - private readonly struct LoadAbsolute : IUnaryOperator + private readonly struct AbsoluteOperator : IUnaryOperator { public static float Invoke(float x) => MathF.Abs(x); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs index ba3fc69bab527f..ed8b3aea0d560f 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.netstandard.cs @@ -10,6 +10,12 @@ public static partial class TensorPrimitives { private static unsafe bool IsNegative(float f) => *(int*)&f < 0; + private static float MaxMagnitude(float x, float y) => MathF.Abs(x) >= MathF.Abs(y) ? x : y; + + private static float MinMagnitude(float x, float y) => MathF.Abs(x) < MathF.Abs(y) ? x : y; + + private static float Log2(float x) => MathF.Log(x, 2); + private static float CosineSimilarityCore(ReadOnlySpan x, ReadOnlySpan y) { // Compute the same as: @@ -551,19 +557,19 @@ public Vector Invoke(Vector x, Vector y) public Vector Invoke(Vector x, Vector y, Vector z) => (x * y) + z; } - private readonly struct LoadIdentity : IUnaryOperator + private readonly struct IdentityOperator : IUnaryOperator { public float Invoke(float x) => x; public Vector Invoke(Vector x) => x; } - private readonly struct LoadSquared : IUnaryOperator + private readonly struct SquaredOperator : IUnaryOperator { public float Invoke(float x) => x * x; public Vector Invoke(Vector x) => x * x; } - private readonly struct LoadAbsolute : IUnaryOperator + private readonly struct AbsoluteOperator : IUnaryOperator { public float Invoke(float x) => MathF.Abs(x); diff --git a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs index 181d152e6ae979..777ab49609856e 100644 --- a/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs +++ b/src/libraries/System.Numerics.Tensors/tests/TensorPrimitivesTests.cs @@ -15,6 +15,9 @@ public static partial class TensorPrimitivesTests { private const double Tolerance = 0.0001; + public static IEnumerable TensorLengthsIncluding0 => + TensorLengths.Concat(new object[][] { [0] }); + public static IEnumerable TensorLengths => from length in Enumerable.Range(1, 128) select new object[] { length }; @@ -45,7 +48,7 @@ private static float NextSingle() } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void AddTwoTensors(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -83,7 +86,7 @@ public static void AddTwoTensors_ThrowsForTooShortDestination(int tensorLength) } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void AddTensorAndScalar(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -110,7 +113,7 @@ public static void AddTensorAndScalar_ThrowsForTooShortDestination(int tensorLen } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void SubtractTwoTensors(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -148,7 +151,7 @@ public static void SubtractTwoTensors_ThrowsForTooShortDestination(int tensorLen } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void SubtractTensorAndScalar(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -175,7 +178,7 @@ public static void SubtractTensorAndScalar_ThrowsForTooShortDestination(int tens } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void MultiplyTwoTensors(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -213,7 +216,7 @@ public static void MultiplyTwoTensors_ThrowsForTooShortDestination(int tensorLen } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void MultiplyTensorAndScalar(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -240,7 +243,7 @@ public static void MultiplyTensorAndScalar_ThrowsForTooShortDestination(int tens } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void DivideTwoTensors(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -278,7 +281,7 @@ public static void DivideTwoTensors_ThrowsForTooShortDestination(int tensorLengt } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void DivideTensorAndScalar(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -305,7 +308,7 @@ public static void DivideTensorAndScalar_ThrowsForTooShortDestination(int tensor } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void NegateTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -330,7 +333,7 @@ public static void NegateTensor_ThrowsForTooShortDestination(int tensorLength) } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void AddTwoTensorsAndMultiplyWithThirdTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -383,7 +386,7 @@ public static void AddTwoTensorsAndMultiplyWithThirdTensor_ThrowsForTooShortDest } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void AddTwoTensorsAndMultiplyWithScalar(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -424,7 +427,7 @@ public static void AddTwoTensorsAndMultiplyWithScalar_ThrowsForTooShortDestinati } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void AddTensorAndScalarAndMultiplyWithTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -465,7 +468,7 @@ public static void AddTensorAndScalarAndMultiplyWithTensor_ThrowsForTooShortDest } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void MultiplyTwoTensorsAndAddWithThirdTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -518,7 +521,7 @@ public static void MultiplyTwoTensorsAndAddWithThirdTensor_ThrowsForTooShortDest } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void MultiplyTwoTensorsAndAddWithScalar(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -547,7 +550,7 @@ public static void MultiplyTwoTensorsAndAddWithScalar_ThrowsForTooShortDestinati } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void MultiplyTensorAndScalarAndAddWithTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -576,7 +579,7 @@ public static void MultiplyTensorAndScalarAndAddWithTensor_ThrowsForTooShortDest } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void ExpTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -601,7 +604,7 @@ public static void ExpTensor_ThrowsForTooShortDestination(int tensorLength) } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void LogTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -625,8 +628,33 @@ public static void LogTensor_ThrowsForTooShortDestination(int tensorLength) AssertExtensions.Throws("destination", () => TensorPrimitives.Log(x, destination)); } + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] + public static void Log2(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Log2(x, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Log(x[i], 2), destination[i], Tolerance); + } + } + [Theory] [MemberData(nameof(TensorLengths))] + public static void Log2_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Log2(x, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] public static void CoshTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -651,7 +679,7 @@ public static void CoshTensor_ThrowsForTooShortDestination(int tensorLength) } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void SinhTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -676,7 +704,7 @@ public static void SinhTensor_ThrowsForTooShortDestination(int tensorLength) } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void TanhTensor(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -809,7 +837,7 @@ public static void Dot_KnownValues(float[] x, float[] y, float expectedResult) } [Theory] - [MemberData(nameof(TensorLengths))] + [MemberData(nameof(TensorLengthsIncluding0))] public static void Dot(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -830,14 +858,14 @@ public static void Dot(int tensorLength) [InlineData(new float[] { 3 }, 3)] [InlineData(new float[] { 3, 4, 1, 2 }, 5.477226)] [InlineData(new float[] { }, 0f)] - public static void L2Normalize_KnownValues(float[] x, float expectedResult) + public static void Norm_KnownValues(float[] x, float expectedResult) { - Assert.Equal(expectedResult, TensorPrimitives.L2Normalize(x), Tolerance); + Assert.Equal(expectedResult, TensorPrimitives.Norm(x), Tolerance); } [Theory] - [MemberData(nameof(TensorLengths))] - public static void L2Normalize(int tensorLength) + [MemberData(nameof(TensorLengthsIncluding0))] + public static void Norm(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); @@ -847,7 +875,7 @@ public static void L2Normalize(int tensorLength) sumOfSquares += x[i] * x[i]; } - Assert.Equal(Math.Sqrt(sumOfSquares), TensorPrimitives.L2Normalize(x), Tolerance); + Assert.Equal(Math.Sqrt(sumOfSquares), TensorPrimitives.Norm(x), Tolerance); } [Theory] @@ -1160,6 +1188,44 @@ public static void Max_Negative0LesserThanPositive0() Assert.Equal(1, TensorPrimitives.Max([-1, -0f, 1])); } + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] + public static void Max_TwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Max(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Max(x[i], y[i]), destination[i], Tolerance); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Max_TwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.Max(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Max_TwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Max(x, y, destination)); + } + [Fact] public static void MaxMagnitude_ThrowsForEmpty() { @@ -1172,14 +1238,16 @@ public static void MaxMagnitude(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); - Assert.Equal(Enumerable.Max(MemoryMarshal.ToEnumerable(x.Memory), MathF.Abs), TensorPrimitives.MaxMagnitude(x)); - - float max = 0; - foreach (float f in x.Span) + int index = 0; + for (int i = 0; i < x.Length; i++) { - max = Math.Max(max, MathF.Abs(f)); + if (MathF.Abs(x[i]) >= MathF.Abs(x[index])) + { + index = i; + } } - Assert.Equal(max, TensorPrimitives.MaxMagnitude(x)); + + Assert.Equal(x[index], TensorPrimitives.MaxMagnitude(x), Tolerance); } [Theory] @@ -1199,12 +1267,50 @@ public static void MaxMagnitude_Negative0LesserThanPositive0() { Assert.Equal(+0f, TensorPrimitives.MaxMagnitude([-0f, +0f])); Assert.Equal(+0f, TensorPrimitives.MaxMagnitude([+0f, -0f])); - Assert.Equal(1, TensorPrimitives.MaxMagnitude([-1, -0f])); + Assert.Equal(-1, TensorPrimitives.MaxMagnitude([-1, -0f])); Assert.Equal(1, TensorPrimitives.MaxMagnitude([-1, -0f, 1])); Assert.Equal(0f, TensorPrimitives.MaxMagnitude([-0f, -0f, -0f, -0f, -0f, 0f])); Assert.Equal(1, TensorPrimitives.MaxMagnitude([-0f, -0f, -0f, -0f, -1, -0f, 0f, 1])); } + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] + public static void MaxMagnitude_TwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.MaxMagnitude(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Abs(x[i]) >= MathF.Abs(y[i]) ? x[i] : y[i], destination[i], Tolerance); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MaxMagnitude_TwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.MaxMagnitude(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MaxMagnitude_TwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.MaxMagnitude(x, y, destination)); + } + [Fact] public static void Min_ThrowsForEmpty() { @@ -1248,6 +1354,44 @@ public static void Min_Negative0LesserThanPositive0() Assert.Equal(-1, TensorPrimitives.Min([-1, -0f, 1])); } + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] + public static void Min_TwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Min(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Min(x[i], y[i]), destination[i], Tolerance); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Min_TwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.Min(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Min_TwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Min(x, y, destination)); + } + [Fact] public static void MinMagnitude_ThrowsForEmpty() { @@ -1260,14 +1404,16 @@ public static void MinMagnitude(int tensorLength) { using BoundedMemory x = CreateAndFillTensor(tensorLength); - Assert.Equal(Enumerable.Min(MemoryMarshal.ToEnumerable(x.Memory), MathF.Abs), TensorPrimitives.MinMagnitude(x)); - - float min = float.PositiveInfinity; - foreach (float f in x.Span) + int index = 0; + for (int i = 0; i < x.Length; i++) { - min = Math.Min(min, MathF.Abs(f)); + if (MathF.Abs(x[i]) < MathF.Abs(x[index])) + { + index = i; + } } - Assert.Equal(min, TensorPrimitives.MinMagnitude(x)); + + Assert.Equal(x[index], TensorPrimitives.MinMagnitude(x), Tolerance); } [Theory] @@ -1291,6 +1437,44 @@ public static void MinMagnitude_Negative0LesserThanPositive0() Assert.Equal(0, TensorPrimitives.MinMagnitude([-1, -0f, 1])); } + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] + public static void MinMagnitude_TwoTensors(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.MinMagnitude(x, y, destination); + + for (int i = 0; i < tensorLength; i++) + { + Assert.Equal(MathF.Abs(x[i]) < MathF.Abs(y[i]) ? x[i] : y[i], destination[i], Tolerance); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MinMagnitude_TwoTensors_ThrowsForMismatchedLengths(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength - 1); + using BoundedMemory destination = CreateTensor(tensorLength); + + Assert.Throws(() => TensorPrimitives.MinMagnitude(x, y, destination)); + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void MinMagnitude_TwoTensors_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory y = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.MinMagnitude(x, y, destination)); + } + [Fact] public static void Product_ThrowsForEmpty() { @@ -1480,5 +1664,30 @@ public static void SumOfMagnitudes_KnownValues() Assert.Equal(6, TensorPrimitives.SumOfMagnitudes([-3, 0, 3])); Assert.Equal(float.NaN, TensorPrimitives.SumOfMagnitudes([-3, float.NaN, 3])); } + + [Theory] + [MemberData(nameof(TensorLengthsIncluding0))] + public static void Abs(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength); + + TensorPrimitives.Abs(x, destination); + + for (int i = 0; i < x.Length; i++) + { + Assert.Equal(MathF.Abs(x[i]), destination[i], Tolerance); + } + } + + [Theory] + [MemberData(nameof(TensorLengths))] + public static void Abs_ThrowsForTooShortDestination(int tensorLength) + { + using BoundedMemory x = CreateAndFillTensor(tensorLength); + using BoundedMemory destination = CreateTensor(tensorLength - 1); + + AssertExtensions.Throws("destination", () => TensorPrimitives.Abs(x, destination)); + } } } From 40ccd8b848225e001d3066a898da3bbca734e320 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Sep 2023 20:20:42 -0700 Subject: [PATCH 304/345] [release/8.0-rc2] Make HostModel PEUtils always read/write little endian (#92441) * Make HostModel PEUtils always read/write little endian * PR feeback - helper methods --------- Co-authored-by: Elinor Fung --- .../AppHost/PEUtils.cs | 121 ++++++------------ .../AppHostUpdateTests.cs | 6 +- 2 files changed, 44 insertions(+), 83 deletions(-) diff --git a/src/installer/managed/Microsoft.NET.HostModel/AppHost/PEUtils.cs b/src/installer/managed/Microsoft.NET.HostModel/AppHost/PEUtils.cs index 0d0b33ed55569e..1bfc80fcfca492 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/AppHost/PEUtils.cs +++ b/src/installer/managed/Microsoft.NET.HostModel/AppHost/PEUtils.cs @@ -1,8 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Buffers.Binary; using System.IO; using System.IO.MemoryMappedFiles; +using System.Reflection.PortableExecutable; namespace Microsoft.NET.HostModel.AppHost { @@ -15,29 +18,13 @@ public static class PEUtils /// true if the accessor represents a PE image, false otherwise. internal static unsafe bool IsPEImage(MemoryMappedViewAccessor accessor) { - byte* pointer = null; + if (accessor.Capacity < PEOffsets.DosStub.PESignatureOffset + sizeof(uint)) + return false; - try - { - accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer); - byte* bytes = pointer + accessor.PointerOffset; - - // https://en.wikipedia.org/wiki/Portable_Executable - // Validate that we're looking at Windows PE file - if (((ushort*)bytes)[0] != PEOffsets.DosImageSignature - || accessor.Capacity < PEOffsets.DosStub.PESignatureOffset + sizeof(uint)) - { - return false; - } - return true; - } - finally - { - if (pointer != null) - { - accessor.SafeMemoryMappedViewHandle.ReleasePointer(); - } - } + // https://en.wikipedia.org/wiki/Portable_Executable + // Validate that we're looking at Windows PE file + ushort signature = AsLittleEndian(accessor.ReadUInt16(0)); + return signature == PEOffsets.DosImageSignature; } public static bool IsPEImage(string filePath) @@ -60,40 +47,15 @@ public static bool IsPEImage(string filePath) /// The memory accessor which has the apphost file opened. internal static unsafe void SetWindowsGraphicalUserInterfaceBit(MemoryMappedViewAccessor accessor) { - byte* pointer = null; - - try - { - accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer); - byte* bytes = pointer + accessor.PointerOffset; - - // https://en.wikipedia.org/wiki/Portable_Executable - uint peHeaderOffset = ((uint*)(bytes + PEOffsets.DosStub.PESignatureOffset))[0]; - - if (accessor.Capacity < peHeaderOffset + PEOffsets.PEHeader.Subsystem + sizeof(ushort)) - { - throw new AppHostNotPEFileException("Subsystem offset out of file range."); - } - - ushort* subsystem = ((ushort*)(bytes + peHeaderOffset + PEOffsets.PEHeader.Subsystem)); - - // https://docs.microsoft.com/en-us/windows/desktop/Debug/pe-format#windows-subsystem - // The subsystem of the prebuilt apphost should be set to CUI - if (subsystem[0] != (ushort)PEOffsets.Subsystem.WindowsCui) - { - throw new AppHostNotCUIException(subsystem[0]); - } - - // Set the subsystem to GUI - subsystem[0] = (ushort)PEOffsets.Subsystem.WindowsGui; - } - finally - { - if (pointer != null) - { - accessor.SafeMemoryMappedViewHandle.ReleasePointer(); - } - } + // https://learn.microsoft.com/windows/win32/debug/pe-format#windows-subsystem + // The subsystem of the prebuilt apphost should be set to CUI + uint peHeaderOffset; + ushort subsystem = GetWindowsSubsystem(accessor, out peHeaderOffset); + if (subsystem != (ushort)Subsystem.WindowsCui) + throw new AppHostNotCUIException(subsystem); + + // Set the subsystem to GUI + accessor.Write(peHeaderOffset + PEOffsets.PEHeader.Subsystem, AsLittleEndian((ushort)Subsystem.WindowsGui)); } public static unsafe void SetWindowsGraphicalUserInterfaceBit(string filePath) @@ -113,32 +75,7 @@ public static unsafe void SetWindowsGraphicalUserInterfaceBit(string filePath) /// The memory accessor which has the apphost file opened. internal static unsafe ushort GetWindowsGraphicalUserInterfaceBit(MemoryMappedViewAccessor accessor) { - byte* pointer = null; - - try - { - accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer); - byte* bytes = pointer + accessor.PointerOffset; - - // https://en.wikipedia.org/wiki/Portable_Executable - uint peHeaderOffset = ((uint*)(bytes + PEOffsets.DosStub.PESignatureOffset))[0]; - - if (accessor.Capacity < peHeaderOffset + PEOffsets.PEHeader.Subsystem + sizeof(ushort)) - { - throw new AppHostNotPEFileException("Subsystem offset out of file range."); - } - - ushort* subsystem = ((ushort*)(bytes + peHeaderOffset + PEOffsets.PEHeader.Subsystem)); - - return subsystem[0]; - } - finally - { - if (pointer != null) - { - accessor.SafeMemoryMappedViewHandle.ReleasePointer(); - } - } + return GetWindowsSubsystem(accessor, out _); } public static unsafe ushort GetWindowsGraphicalUserInterfaceBit(string filePath) @@ -151,5 +88,25 @@ public static unsafe ushort GetWindowsGraphicalUserInterfaceBit(string filePath) } } } + + private static ushort GetWindowsSubsystem(MemoryMappedViewAccessor accessor, out uint peHeaderOffset) + { + // https://en.wikipedia.org/wiki/Portable_Executable + if (accessor.Capacity < PEOffsets.DosStub.PESignatureOffset + sizeof(uint)) + throw new AppHostNotPEFileException("PESignature offset out of file range."); + + peHeaderOffset = AsLittleEndian(accessor.ReadUInt32(PEOffsets.DosStub.PESignatureOffset)); + if (accessor.Capacity < peHeaderOffset + PEOffsets.PEHeader.Subsystem + sizeof(ushort)) + throw new AppHostNotPEFileException("Subsystem offset out of file range."); + + // https://learn.microsoft.com/windows/win32/debug/pe-format#windows-subsystem + return AsLittleEndian(accessor.ReadUInt16(peHeaderOffset + PEOffsets.PEHeader.Subsystem)); + } + + private static ushort AsLittleEndian(ushort value) + => BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); + + private static uint AsLittleEndian(uint value) + => BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value); } } diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs index 232410be8f2596..b4d038b99b5ce3 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUpdateTests.cs @@ -11,6 +11,7 @@ using Microsoft.NET.HostModel.AppHost; using Microsoft.DotNet.CoreSetup.Test; using System.Diagnostics; +using System.Reflection.PortableExecutable; namespace Microsoft.NET.HostModel.Tests { @@ -111,7 +112,9 @@ public void ItCanSetWindowsGUISubsystem() BitConverter .ToUInt16(File.ReadAllBytes(destinationFilePath), SubsystemOffset) .Should() - .Be(2); + .Be((ushort)Subsystem.WindowsGui); + + Assert.Equal((ushort)Subsystem.WindowsGui, PEUtils.GetWindowsGraphicalUserInterfaceBit(destinationFilePath)); } } @@ -153,6 +156,7 @@ public void ItFailsToSetGUISubsystemWithWrongDefault() string destinationFilePath = Path.Combine(testDirectory.Path, "DestinationAppHost.exe.mock"); string appBinaryFilePath = "Test/App/Binary/Path.dll"; + Assert.Equal(42, PEUtils.GetWindowsGraphicalUserInterfaceBit(sourceAppHostMock)); Assert.Throws(() => HostWriter.CreateAppHost( sourceAppHostMock, From 78a61f99614cbbe6eca330e4005764d488e11338 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:44:12 -0500 Subject: [PATCH 305/345] Update dependencies from https://github.com/dotnet/source-build-externals build 20230921.2 (#92476) Microsoft.SourceBuild.Intermediate.source-build-externals From Version 8.0.0-alpha.1.23469.1 -> To Version 8.0.0-alpha.1.23471.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e40acd650b02cb..4ff6b9f311612d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -100,9 +100,9 @@ d825c6693d4e26f63aaa93c3c1d057faa098e347 - + https://github.com/dotnet/source-build-externals - c42a7ce3b6fa02957e7b4ef995c5c2a9a23d294c + 6dbf3aaa0fc9664df86462f5c70b99800934fccd diff --git a/eng/Versions.props b/eng/Versions.props index 50c7ee67b3e1bf..0cc312c22fe154 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -10,7 +10,8 @@ 7.0.11 6.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet7)').Build),11)) rtm - + + false release From fed0f788e7c0e24a78e11d708279eaa242098a11 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 08:45:56 -0700 Subject: [PATCH 306/345] Update dependencies from https://github.com/dotnet/emsdk build 20230921.3 (#92454) Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rc.2.23469.4 -> To Version 8.0.0-rc.2.23471.3 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9bedd07535a17d..2582a60b745fef 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,9 +90,9 @@ 89be445dd4936157533ad96bafb95f701430653a - + https://github.com/dotnet/emsdk - ea0e8e8214e9acc0cba7e78a836ed6656f788d11 + 190be5fe0709de5a3507448151c7fc84abff8628 diff --git a/eng/Versions.props b/eng/Versions.props index a7d36117e12b76..38c9e5fd4f1ab9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -238,7 +238,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rc.2.23469.4 + 8.0.0-rc.2.23471.3 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From 1564797c4895bfcc30e67c1c94a04712544b19a3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 09:11:13 -0700 Subject: [PATCH 307/345] [release/8.0] Update dependencies from dotnet/roslyn (#92418) * Update dependencies from https://github.com/dotnet/roslyn build 20230921.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.9 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230921.11 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.2 -> To Version 4.8.0-3.23471.11 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4ff6b9f311612d..dc1ad8042a4d83 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - 9f6f97debe7fe8121a2249f807343d12ef1e4ac6 + bdd9c5ba66b00beebdc3516acc5e29b83efd89af - + https://github.com/dotnet/roslyn - 9f6f97debe7fe8121a2249f807343d12ef1e4ac6 + bdd9c5ba66b00beebdc3516acc5e29b83efd89af - + https://github.com/dotnet/roslyn - 9f6f97debe7fe8121a2249f807343d12ef1e4ac6 + bdd9c5ba66b00beebdc3516acc5e29b83efd89af https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index c0270374896a36..c6a6b57ec67fa2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,9 +44,9 @@ 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. --> - 4.8.0-3.23471.2 - 4.8.0-3.23471.2 - 4.8.0-3.23471.2 + 4.8.0-3.23471.11 + 4.8.0-3.23471.11 + 4.8.0-3.23471.11 diff --git a/eng/Versions.props b/eng/Versions.props index c6a6b57ec67fa2..196aed74ec290a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -158,12 +158,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23465.3 - 1.0.0-prerelease.23465.3 - 1.0.0-prerelease.23465.3 - 1.0.0-prerelease.23465.3 - 1.0.0-prerelease.23465.3 - 1.0.0-prerelease.23465.3 + 1.0.0-prerelease.23471.3 + 1.0.0-prerelease.23471.3 + 1.0.0-prerelease.23471.3 + 1.0.0-prerelease.23471.3 + 1.0.0-prerelease.23471.3 + 1.0.0-prerelease.23471.3 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 From 0717e52526d8a45907f07cf7860d1290f8064558 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:14:27 -0700 Subject: [PATCH 310/345] [release/8.0-rc2] Ensure that embedded broadcast checks the base type of the parent node (#92459) * Ensure that embedded broadcast checks the base type of the parent node * Ensure the regression test exits if AVX2 is not supported * Also handle embedded broadcasts for mismatched memory sizes --------- Co-authored-by: Tanner Gooding --- src/coreclr/jit/lowerxarch.cpp | 19 ++++++-- .../JitBlue/Runtime_92357/Runtime_92357.cs | 47 +++++++++++++++++++ .../Runtime_92357/Runtime_92357.csproj | 8 ++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.csproj diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 30c2a832b94fc1..319238aaec628f 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -8202,10 +8202,12 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre case NI_AVX2_BroadcastScalarToVector256: case NI_AVX512F_BroadcastScalarToVector512: { - var_types baseType = hwintrinsic->GetSimdBaseType(); - if (varTypeIsSmall(baseType)) + var_types parentBaseType = parentNode->GetSimdBaseType(); + var_types childBaseType = hwintrinsic->GetSimdBaseType(); + + if (varTypeIsSmall(parentBaseType) || (genTypeSize(parentBaseType) != genTypeSize(childBaseType))) { - // early return if the base type is not embedded broadcast compatible. + // early return if either base type is not embedded broadcast compatible. return false; } @@ -8213,7 +8215,7 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre if (intrinsicId == NI_SSE3_MoveAndDuplicate) { // NI_SSE3_MoveAndDuplicate is for Vector128 only. - assert(baseType == TYP_DOUBLE); + assert(childBaseType == TYP_DOUBLE); } if (comp->compOpportunisticallyDependsOn(InstructionSet_AVX512F_VL) && @@ -8246,6 +8248,15 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre case NI_AVX_BroadcastScalarToVector128: case NI_AVX_BroadcastScalarToVector256: { + var_types parentBaseType = parentNode->GetSimdBaseType(); + var_types childBaseType = hwintrinsic->GetSimdBaseType(); + + if (varTypeIsSmall(parentBaseType) || (genTypeSize(parentBaseType) != genTypeSize(childBaseType))) + { + // early return if either base type is not embedded broadcast compatible. + return false; + } + return parentNode->OperIsEmbBroadcastCompatible(); } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.cs b/src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.cs new file mode 100644 index 00000000000000..4704441bacce6c --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using Xunit; + +public static class Runtime_92357 +{ + [Fact] + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public static void Problem() + { + if (!Avx2.IsSupported) + { + return; + } + + int y1 = 5; + + Vector256 actual1 = Test1(Vector256.Create((short)1), ref y1); + Vector256 expected1 = Vector256.Create(10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0); + + Assert.Equal(expected1, actual1); + + long y2 = 5; + + Vector256 actual2 = Test2(Vector256.Create((int)1), ref y2); + Vector256 expected2 = Vector256.Create(10, 0, 10, 0, 10, 0, 10, 0); + + Assert.Equal(expected2, actual2); + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public static Vector256 Test1(Vector256 x, ref int y) + { + return Avx2.MultiplyLow(x + x, Vector256.Create(y).AsInt16()); + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + public static Vector256 Test2(Vector256 x, ref long y) + { + return Avx2.MultiplyLow(x + x, Vector256.Create(y).AsInt32()); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92357/Runtime_92357.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From 873b3cca0a6ac461f1f6df70622e3b4703e6e493 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:16:16 -0700 Subject: [PATCH 311/345] [release/8.0-rc2] Do not call SignalSession on invalid session IDs (#92444) * Update EventPipeEventDispatcher.cs * Update EventPipeEventDispatcher.cs --------- Co-authored-by: David Mason --- .../Tracing/EventPipeEventDispatcher.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs index efd4b8cfb656dd..708c5afc1bc70e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs @@ -142,12 +142,15 @@ private void SetStopDispatchTask() { Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); - if (m_dispatchTask != null) + if (m_dispatchTaskCancellationSource?.IsCancellationRequested ?? true) { - Debug.Assert(m_dispatchTaskCancellationSource != null); - m_dispatchTaskCancellationSource?.Cancel(); - EventPipeInternal.SignalSession(m_sessionID); + return; } + + Debug.Assert(m_sessionID != 0); + m_dispatchTaskCancellationSource.Cancel(); + EventPipeInternal.SignalSession(m_sessionID); + m_sessionID = 0; } private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, Task? previousDispatchTask, CancellationToken token) @@ -187,8 +190,12 @@ private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syn } } - // Disable the old session. This can happen asynchronously since we aren't using the old session anymore - EventPipeInternal.Disable(sessionID); + lock (m_dispatchControlLock) + { + // Disable the old session. This can happen asynchronously since we aren't using the old session + // anymore. We take the lock to make sure we don't call SignalSession on an invalid session ID. + EventPipeInternal.Disable(sessionID); + } } /// From 974edf97294f3fb1b74cfddaf0275a657886224b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:25:30 -0700 Subject: [PATCH 312/345] [release/8.0-rc2] Ensure Bind can handle null from GetSection (#92477) * Ensure Bind can handle null from GetSection IConfiguration instances may return a null value from GetSection. We were not handling this and would throw a NullReferenceException. * Address feedback * Remove Moq from ConfigBinder tests --------- Co-authored-by: Eric StJohn --- .../src/ConfigurationBinder.cs | 5 +++ .../ConfigurationBinderTests.TestClasses.cs | 6 +++ .../tests/Common/ConfigurationBinderTests.cs | 38 ++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index 74365d8084aa3d..dfc35d80208553 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -298,6 +298,11 @@ private static void BindInstance( return; } + if (config is null) + { + return; + } + var section = config as IConfigurationSection; string? configValue = section?.Value; if (configValue != null && TryConvertValue(type, configValue, section?.Path, out object? convertedValue, out Exception? error)) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs index f47cdbe6dbbb54..48474033ec1f8e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs @@ -888,5 +888,11 @@ public int MyIntProperty } } + public class SimplePoco + { + public string A { get; set; } + public string B { get; set; } + } + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 7c955e789184c8..7e635c1f0bdaa0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -11,6 +11,7 @@ #if BUILDING_SOURCE_GENERATOR_TESTS using Microsoft.Extensions.Configuration; #endif +using Microsoft.Extensions.Configuration.Memory; using Microsoft.Extensions.Configuration.Test; using Xunit; @@ -1767,7 +1768,7 @@ public void EnsureCallingThePropertySetter() Assert.Equal(0, options.OtherCodeNullable); Assert.Equal("default", options.OtherCodeString); Assert.Null(options.OtherCodeNull); - Assert.Null(options.OtherCodeUri); + Assert.Null(options.OtherCodeUri); } [Fact] @@ -2238,7 +2239,7 @@ void TestUntypedOverloads(IConfiguration? configuration, string? key) Assert.Throws(() => configuration.GetValue(typeof(GeolocationClass), key, new GeolocationClass())); Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key)); Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key, defaultValue: null)); - Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key, default(Geolocation))); + Assert.Throws(() => configuration.GetValue(typeof(Geolocation), key, default(Geolocation))); } } @@ -2404,5 +2405,38 @@ public void SharedChildInstance() config.GetSection("A").Bind(instance); Assert.Equal("localhost", instance.ConnectionString); } + + [Fact] + public void CanBindToMockConfigurationSection() + { + const string expectedA = "hello"; + + var configSource = new MemoryConfigurationSource() + { + InitialData = new Dictionary() + { + [$":{nameof(SimplePoco.A)}"] = expectedA, + } + }; + var configRoot = new MockConfigurationRoot(new[] { configSource.Build(null) }); + var configSection = new ConfigurationSection(configRoot, string.Empty); + + SimplePoco result = new(); + configSection.Bind(result); + + Assert.Equal(expectedA, result.A); + Assert.Equal(default(string), result.B); + } + + // a mock configuration root that will return null for undefined Sections, + // as is common when Configuration interfaces are mocked + class MockConfigurationRoot : ConfigurationRoot, IConfigurationRoot + { + public MockConfigurationRoot(IList providers) : base(providers) + { } + + IConfigurationSection IConfiguration.GetSection(string key) => + this[key] is null ? null : new ConfigurationSection(this, key); + } } } From 4f51a33e6fb22b88a05e20593072f83bc71a445a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:04:25 -0700 Subject: [PATCH 313/345] Update dependencies from https://github.com/dotnet/roslyn build 20230922.2 (#92488) Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23471.11 -> To Version 4.8.0-3.23472.2 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c768ef801d3b43..3894120b6e9cf6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - bdd9c5ba66b00beebdc3516acc5e29b83efd89af + aa7e4da5341196be494ca4bb0c719d7bef3e396a - + https://github.com/dotnet/roslyn - bdd9c5ba66b00beebdc3516acc5e29b83efd89af + aa7e4da5341196be494ca4bb0c719d7bef3e396a - + https://github.com/dotnet/roslyn - bdd9c5ba66b00beebdc3516acc5e29b83efd89af + aa7e4da5341196be494ca4bb0c719d7bef3e396a https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index 196aed74ec290a..1f94efa53a6898 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,9 +44,9 @@ 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. --> - 4.8.0-3.23471.11 - 4.8.0-3.23471.11 - 4.8.0-3.23471.11 + 4.8.0-3.23472.2 + 4.8.0-3.23472.2 + 4.8.0-3.23472.2 - 3.11.0-beta1.23468.1 - 8.0.0-preview.23468.1 + 3.11.0-beta1.23472.1 + 8.0.0-preview.23472.1 - 3.11.0-beta1.23468.1 - 8.0.0-preview.23468.1 + 3.11.0-beta1.23472.1 + 8.0.0-preview.23472.1 8.0.0-rc.1.23406.6 8.0.0-preview.7.23325.2 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 6.0.0 1.1.1 @@ -220,38 +220,38 @@ 2.2.2 8.0.0-alpha.1.23468.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 - 8.0.0-rc.2.23471.3 + 8.0.0-rc.2.23473.3 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 3.1.7 1.0.406601 From a3d5300baee03169bf737cfc4e9b1f7dbece4d05 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 11:11:14 -0500 Subject: [PATCH 318/345] Update dependencies from https://github.com/dotnet/emsdk build 20230923.1 (#92532) Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rtm.23470.1 -> To Version 8.0.0-rtm.23473.1 Dependency coherency updates runtime.linux-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.win-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.win-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.osx-arm64.Microsoft.NETCore.Runtime.ObjWriter,runtime.osx-x64.Microsoft.NETCore.Runtime.ObjWriter,runtime.linux-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.win-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.win-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.osx-arm64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.osx-x64.Microsoft.NETCore.Runtime.JIT.Tools,runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-musl-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.linux-musl-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.win-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.osx-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.osx-arm64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools,runtime.osx-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Sdk,runtime.osx-x64.Microsoft.NETCore.Runtime.Mono.LLVM.Tools From Version 16.0.5-alpha.1.23423.1 -> To Version 16.0.5-alpha.1.23472.2 (parent: Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 124 ++++++++++++++++++++-------------------- eng/Versions.props | 62 ++++++++++---------- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8a39a384f4ad5e..30dcddeebd5e40 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,69 +12,69 @@ https://github.com/dotnet/wcf 7f504aabb1988e9a093c1e74d8040bd52feb2f01 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 https://github.com/dotnet/command-line-api @@ -90,9 +90,9 @@ 89be445dd4936157533ad96bafb95f701430653a - + https://github.com/dotnet/emsdk - 446eeb331fcbf2f48c14a377601a8ab950ec942e + 41db2322780b16e4ddadcebca41dc86c7806ed9a @@ -233,61 +233,61 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 - + https://github.com/dotnet/llvm-project - 08a449c9a9bf593b29fc05de2f424e6882320e5d + 2e6bfc3d59a6c80e3fa90a703e23bd4dab707756 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 01481f4c419ac5..772c606514e126 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -110,14 +110,14 @@ 8.0.0-rc.1.23406.6 8.0.0-preview.7.23325.2 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 6.0.0 1.1.1 @@ -222,38 +222,38 @@ 2.2.2 8.0.0-alpha.1.23468.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 - 8.0.0-rtm.23470.1 + 8.0.0-rtm.23473.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda 1.0.0-v3.14.0.5722 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 - 16.0.5-alpha.1.23423.1 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 + 16.0.5-alpha.1.23472.2 3.1.7 1.0.406601 From 7778148a7fbfe4d05a85a181b54054a02a182607 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:04:51 -0700 Subject: [PATCH 319/345] Update dependencies from https://github.com/dotnet/source-build-externals build 20230925.1 (#92641) Microsoft.SourceBuild.Intermediate.source-build-externals From Version 8.0.0-alpha.1.23471.2 -> To Version 8.0.0-alpha.1.23475.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 30dcddeebd5e40..ecea0bfbd34317 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -100,9 +100,9 @@ 7b55da982fc6e71c1776c4de89111aee0eecb45a - + https://github.com/dotnet/source-build-externals - 6dbf3aaa0fc9664df86462f5c70b99800934fccd + e04156dbe14f882a80d4499dbebd45ab156b6c3c From 849fc57e8810723fc991460ef954b496ffdf366c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:52:34 -0700 Subject: [PATCH 320/345] [release/8.0] Update dependencies from dotnet/emsdk dotnet/hotreload-utils (#92606) * Update dependencies from https://github.com/dotnet/emsdk build 20230925.3 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rtm.23473.1 -> To Version 8.0.0-rtm.23475.3 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20230925.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 8.0.0-alpha.0.23461.1 -> To Version 8.0.0-alpha.0.23475.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ecea0bfbd34317..a4ab920e969679 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -90,9 +90,9 @@ 89be445dd4936157533ad96bafb95f701430653a - + https://github.com/dotnet/emsdk - 41db2322780b16e4ddadcebca41dc86c7806ed9a + 0a2aae889f5ce2803fa227e13963b3fbf3ccb6b0 @@ -350,9 +350,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization ee166d79f3a269d2a1c6b7d400df7e284b1aa67b - + https://github.com/dotnet/hotreload-utils - 4b29cfaccdab45442e15f3b84f75bc9c10ee79b3 + 6c20c1d568568b9b2da84f878ac9cb4a48aaa4e5 https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index 772c606514e126..0a745db24ef032 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -186,7 +186,7 @@ 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 - 8.0.0-alpha.0.23468.2 + 8.0.0-alpha.0.23475.1 2.4.2 1.0.0 2.4.5 @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rtm.23473.1 + 8.0.0-rtm.23475.3 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda From 0933e300f0c0647a15a0433f1a3b07bcab9882f4 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Tue, 26 Sep 2023 22:45:35 -0400 Subject: [PATCH 321/345] [release/8.0][wasm] Fix regressed file sizes for blazor (#92627) * [wasm] Add getters for __indirect_function_table, and wasmMemory .. so that can work even if they get renamed during minimization. * [wasm] build: Revert to older behavior for WasmNativeStrip The earlier change was done in 678fd6a73756f8438be115898cdd4fe0500e3d18, which changed to pass `-g` to the link step also. But that resulted in increased native file sizes. Changed sizes for the `minimum blazor template - publish` scenario: ``` | Last rc1 run | With the change ----------------------------------------------------------|----------------- |------------------ SOD - Minimum Blazor Template - Publish |8590723.000 bytes |7889806.000 bytes Total Uncompressed _framework |4304274.000 bytes |4202273.000 bytes pub/wwwroot/_framework/dotnet.js |35722.000 bytes |35838.000 bytes pub/wwwroot/_framework/dotnet.native.8.0.0-VERSION.js |239307.000 bytes |134566.000 bytes pub/wwwroot/_framework/dotnet.native.wasm |1174394.000 bytes |1148841.000 bytes pub/wwwroot/_framework/dotnet.runtime.8.0.0-VERSION.js |221356.000 bytes |221712.000 bytes ``` * [wasm] cleanup corresponding tests * [wasm] Remove WasmNativeStrip from wasm.proj as it will have no effect --- .../WasmNativeDefaultsTests.cs | 107 +++++++++++------- src/mono/wasm/build/WasmApp.Native.targets | 28 +++-- src/mono/wasm/runtime/es6/dotnet.es6.pre.js | 4 +- src/mono/wasm/runtime/jiterpreter-jit-call.ts | 2 +- src/mono/wasm/runtime/jiterpreter-support.ts | 7 +- src/mono/wasm/runtime/types/internal.ts | 2 + src/mono/wasm/wasm.proj | 1 - 7 files changed, 91 insertions(+), 60 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmNativeDefaultsTests.cs b/src/mono/wasm/Wasm.Build.Tests/WasmNativeDefaultsTests.cs index 5efd84085b8863..4bbea5dff8a926 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmNativeDefaultsTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmNativeDefaultsTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using Xunit; using Xunit.Abstractions; @@ -12,6 +13,7 @@ namespace Wasm.Build.Tests { public class WasmNativeDefaultsTests : TestMainJsTestBase { + private static Regex s_regex = new("\\*\\* WasmBuildNative:.*"); public WasmNativeDefaultsTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext) { @@ -39,19 +41,20 @@ public static TheoryData SettingDifferentFromV // Config=Release always causes relinking when publishing bool publishValue = forPublish && config == "Release" ? true : false; // Setting the default value from the runtime pack shouldn't trigger relinking - data.Add(config, $"<{defaultPair.propertyName}>{defaultPair.defaultValueInRuntimePack}", + data.Add(config, $"<{defaultPair.propertyName}>{defaultPair.defaultValueInRuntimePack.ToString().ToLower()}", /*aot*/ false, /*build*/ false, /*publish*/ publishValue); // Leaving the property unset, so checking the default data.Add(config, "", /*aot*/ false, /*build*/ false, /*publish*/ publishValue); // Setting the !default value should trigger relinking - data.Add(config, $"<{defaultPair.propertyName}>{!defaultPair.defaultValueInRuntimePack}", + data.Add(config, $"<{defaultPair.propertyName}>{(!defaultPair.defaultValueInRuntimePack).ToString().ToLower()}", /*aot*/ false, /*build*/ true, /*publish*/ true); } } return data; } + public static TheoryData DefaultsTestData(bool forPublish) { TheoryData data = new() @@ -93,45 +96,34 @@ public static TheoryData DefaultsTestData(bool return data; } +#pragma warning disable xUnit1026 // For unused *buildValue*, and *publishValue* parameters [Theory] [MemberData(nameof(DefaultsTestData), parameters: false)] [MemberData(nameof(SettingDifferentFromValuesInRuntimePack), parameters: false)] public void DefaultsWithBuild(string config, string extraProperties, bool aot, bool expectWasmBuildNativeForBuild, bool expectWasmBuildNativeForPublish) { - string output = CheckWasmNativeDefaultValue("native_defaults_build", config, extraProperties, aot, dotnetWasmFromRuntimePack: !expectWasmBuildNativeForPublish, publish: false); - - bool expectedWasmNativeStripValue = true; - if (/*isBuild && */ expectWasmBuildNativeForBuild && config == "Debug") - expectedWasmNativeStripValue = false; + (string output, string? line) = CheckWasmNativeDefaultValue("native_defaults_build", config, extraProperties, aot, dotnetWasmFromRuntimePack: !expectWasmBuildNativeForBuild, publish: false); - // bool expectedWasmNativeStripValue = !(wasmBuildNativeForBuild && config == "Debug"); - // for build - Assert.Contains($"** WasmBuildNative: '{expectWasmBuildNativeForBuild.ToString().ToLower()}', WasmNativeStrip: '{expectedWasmNativeStripValue.ToString().ToLower()}', WasmBuildingForNestedPublish: ''", output); - Assert.Contains("Stopping the build", output); + InferAndCheckPropertyValues(line, isPublish: false, wasmBuildNative: expectWasmBuildNativeForBuild, config: config); } -#pragma warning disable xUnit1026 // For unused *buildValue* parameter [Theory] [MemberData(nameof(DefaultsTestData), parameters: true)] [MemberData(nameof(SettingDifferentFromValuesInRuntimePack), parameters: true)] public void DefaultsWithPublish(string config, string extraProperties, bool aot, bool expectWasmBuildNativeForBuild, bool expectWasmBuildNativeForPublish) { - string output = CheckWasmNativeDefaultValue("native_defaults_publish", config, extraProperties, aot, dotnetWasmFromRuntimePack: !expectWasmBuildNativeForPublish, publish: true); + (string output, string? line) = CheckWasmNativeDefaultValue("native_defaults_publish", config, extraProperties, aot, dotnetWasmFromRuntimePack: !expectWasmBuildNativeForPublish, publish: true); - // for build - // Assert.DoesNotContain($"** WasmBuildNative: '{buildValue.ToString().ToLower()}', WasmNativeStrip: 'true', WasmBuildingForNestedPublish: ''", output); - // for publish - Assert.Contains($"** WasmBuildNative: '{expectWasmBuildNativeForPublish.ToString().ToLower()}', WasmNativeStrip: 'true', WasmBuildingForNestedPublish: 'true'", output); - Assert.Contains("Stopping the build", output); + InferAndCheckPropertyValues(line, isPublish: true, wasmBuildNative: expectWasmBuildNativeForPublish, config: config); } #pragma warning restore xunit1026 public static TheoryData SetWasmNativeStripExplicitlyTestData(bool publish) => new() { - {"Debug", "true", false, true }, - {"Release", "true", publish, true }, - {"Debug", "false", true, false }, - {"Release", "false", true, false } + {"Debug", "true", /*wasmBuildNative*/ false, /*wasmNativeStrip*/ true }, + {"Release", "true", /*wasmBuildNative*/ publish, /*wasmNativeStrip*/ true }, + {"Debug", "false", /*wasmBuildNative*/ true, /*wasmNativeStrip*/ false }, + {"Release", "false", /*wasmBuildNative*/ true, /*wasmNativeStrip*/ false } }; public static TheoryData SetWasmNativeStripExplicitlyWithWasmBuildNativeTestData() => new() @@ -147,10 +139,13 @@ public void DefaultsWithPublish(string config, string extraProperties, bool aot, [MemberData(nameof(SetWasmNativeStripExplicitlyWithWasmBuildNativeTestData))] public void WasmNativeStripDefaultWithBuild(string config, string extraProperties, bool expectedWasmBuildNativeValue, bool expectedWasmNativeStripValue) { - string output = CheckWasmNativeDefaultValue("native_strip_defaults", config, extraProperties, aot: false, dotnetWasmFromRuntimePack: !expectedWasmBuildNativeValue, publish: false); + (string output, string? line) = CheckWasmNativeDefaultValue("native_strip_defaults", config, extraProperties, aot: false, dotnetWasmFromRuntimePack: !expectedWasmBuildNativeValue, publish: false); - Assert.Contains($"** WasmBuildNative: '{expectedWasmBuildNativeValue.ToString().ToLower()}', WasmNativeStrip: '{expectedWasmNativeStripValue.ToString().ToLower()}', WasmBuildingForNestedPublish: ''", output); - Assert.Contains("Stopping the build", output); + CheckPropertyValues(line, + wasmBuildNative: expectedWasmBuildNativeValue, + wasmNativeStrip: expectedWasmNativeStripValue, + wasmNativeDebugSymbols: true, + wasmBuildingForNestedPublish: null); } [Theory] @@ -158,37 +153,38 @@ public void WasmNativeStripDefaultWithBuild(string config, string extraPropertie [MemberData(nameof(SetWasmNativeStripExplicitlyWithWasmBuildNativeTestData))] public void WasmNativeStripDefaultWithPublish(string config, string extraProperties, bool expectedWasmBuildNativeValue, bool expectedWasmNativeStripValue) { - string output = CheckWasmNativeDefaultValue("native_strip_defaults", config, extraProperties, aot: false, dotnetWasmFromRuntimePack: !expectedWasmBuildNativeValue, publish: true); + (string output, string? line) = CheckWasmNativeDefaultValue("native_strip_defaults", config, extraProperties, aot: false, dotnetWasmFromRuntimePack: !expectedWasmBuildNativeValue, publish: true); - Assert.Contains($"** WasmBuildNative: '{expectedWasmBuildNativeValue.ToString().ToLower()}', WasmNativeStrip: '{expectedWasmNativeStripValue.ToString().ToLower()}', WasmBuildingForNestedPublish: 'true'", output); - Assert.Contains("Stopping the build", output); + CheckPropertyValues(line, + wasmBuildNative: expectedWasmBuildNativeValue, + wasmNativeStrip: expectedWasmNativeStripValue, + wasmNativeDebugSymbols: true, + wasmBuildingForNestedPublish: true); } [Theory] /* always relink */ - [InlineData("Debug", "", /*build*/ true, /*publish*/ true)] - [InlineData("Release", "", /*build*/ true, /*publish*/ true)] - [InlineData("Release", "false", /*build*/ true, /*publish*/ true)] - public void WithNativeReference(string config, string extraProperties, bool buildValue, bool publishValue) + [InlineData("Debug", "", /*publish*/ false)] + [InlineData("Debug", "", /*publish*/ true)] + [InlineData("Release", "", /*publish*/ false)] + [InlineData("Release", "", /*publish*/ true)] + [InlineData("Release", "false", /*publish*/ true)] + public void WithNativeReference(string config, string extraProperties, bool publish) { string nativeLibPath = Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "native-lib.o"); string nativeRefItem = @$""; - string output = CheckWasmNativeDefaultValue("native_defaults_publish", + (string output, string? line) = CheckWasmNativeDefaultValue("native_defaults_publish", config, extraProperties, aot: false, - dotnetWasmFromRuntimePack: !publishValue, - publish: true, + dotnetWasmFromRuntimePack: !publish, + publish: publish, extraItems: nativeRefItem); - // for build - FIXME: - Assert.DoesNotContain($"** WasmBuildNative: '{buildValue.ToString().ToLower()}', WasmBuildingForNestedPublish: ''", output); - // for publish - Assert.Contains($"** WasmBuildNative: '{publishValue.ToString().ToLower()}', WasmNativeStrip: 'true', WasmBuildingForNestedPublish: 'true'", output); - Assert.Contains("Stopping the build", output); + InferAndCheckPropertyValues(line, isPublish: publish, wasmBuildNative: true, config: config); } - private string CheckWasmNativeDefaultValue(string projectName, + private (string, string?) CheckWasmNativeDefaultValue(string projectName, string config, string extraProperties, bool aot, @@ -201,7 +197,7 @@ private string CheckWasmNativeDefaultValue(string projectName, string printValueTarget = @" - + " + (publish ? @"" : @"") @@ -223,7 +219,32 @@ private string CheckWasmNativeDefaultValue(string projectName, BuildOnlyAfterPublish: false, Publish: publish)); - return output; + Assert.Contains("Stopping the build", output); + + Match m = s_regex.Match(output); + Assert.Equal(1, m.Groups.Count); + return (output, m.Success ? m.Groups[0]?.ToString() : null); + } + + private void InferAndCheckPropertyValues(string? line, bool isPublish, bool wasmBuildNative, string config) + { + bool expectedWasmNativeStripValue; + if (!isPublish && wasmBuildNative && config == "Debug") + expectedWasmNativeStripValue = false; + else + expectedWasmNativeStripValue = true; + + CheckPropertyValues(line, wasmBuildNative, expectedWasmNativeStripValue, /*wasmNativeDebugSymbols*/true, isPublish); + } + + private void CheckPropertyValues(string? line, bool wasmBuildNative, bool wasmNativeStrip, bool wasmNativeDebugSymbols, bool? wasmBuildingForNestedPublish) + { + Assert.NotNull(line); + Assert.Contains($"** WasmBuildNative: '{wasmBuildNative.ToString().ToLower()}', " + + $"WasmNativeStrip: '{wasmNativeStrip.ToString().ToLower()}', " + + $"WasmNativeDebugSymbols: '{wasmNativeDebugSymbols.ToString().ToLower()}', " + + $"WasmBuildingForNestedPublish: '{(wasmBuildingForNestedPublish.HasValue && wasmBuildingForNestedPublish == true ? "true" : "")}'", + line); } } } diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 295474566a14a0..73e5720abb01ed 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -22,7 +22,6 @@ $(_BeforeWasmBuildAppDependsOn); _SetupEmscripten; _SetWasmBuildNativeDefaults; - _SetWasmNativeStripDefault; _ReadEmccProps @@ -119,6 +118,7 @@ <_BoolPropertiesThatTriggerRelinking Include="InvariantTimezone" DefaultValueInRuntimePack="false" /> <_BoolPropertiesThatTriggerRelinking Include="InvariantGlobalization" DefaultValueInRuntimePack="false" /> <_BoolPropertiesThatTriggerRelinking Include="WasmNativeStrip" DefaultValueInRuntimePack="true" /> + @@ -133,7 +133,6 @@ true true - false @@ -147,10 +146,23 @@ true + + false + + + true + false + + + + true + true + + @@ -160,14 +172,6 @@ - - - - false - true - - - @@ -178,7 +182,6 @@ <_MonoAotCrossCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','browser-wasm')) <_EmccDefaultFlagsRsp>$([MSBuild]::NormalizePath($(_WasmRuntimePackSrcDir), 'emcc-default.rsp')) <_EmccDefaultLinkFlagsRsp>$([MSBuild]::NormalizePath($(_WasmRuntimePackSrcDir), 'emcc-link.rsp')) - true $(WasmBuildNative) <_WasmICallTablePath>$(_WasmIntermediateOutputPath)icall-table.h @@ -221,7 +224,7 @@ <_EmccCommonFlags Include="$(_DefaultEmccFlags)" /> <_EmccCommonFlags Include="$(EmccFlags)" /> - <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> + <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeStrip)' == 'false'" /> <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" /> <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> @@ -249,6 +252,7 @@ <_EmccCFlags Include="-emit-llvm" /> <_EmccCFlags Include=""-I%(_EmccIncludePaths.Identity)"" /> + <_EmccCFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> <_EmccLDFlags Include="$(EmccLinkOptimizationFlag)" /> diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js index 9eb9b1c6b99e7d..490935d5ca0284 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js @@ -1,3 +1,5 @@ if (_nativeModuleLoaded) throw new Error("Native module already loaded"); _nativeModuleLoaded = true; -createDotnetRuntime = Module = createDotnetRuntime(Module); \ No newline at end of file +createDotnetRuntime = Module = createDotnetRuntime(Module); +Module["getWasmIndirectFunctionTable"] = function () { return wasmTable; } +Module["getMemory"] = function () { return wasmMemory; } diff --git a/src/mono/wasm/runtime/jiterpreter-jit-call.ts b/src/mono/wasm/runtime/jiterpreter-jit-call.ts index eba38843de57ef..af918bedb0cf9c 100644 --- a/src/mono/wasm/runtime/jiterpreter-jit-call.ts +++ b/src/mono/wasm/runtime/jiterpreter-jit-call.ts @@ -281,7 +281,7 @@ export function mono_jiterp_do_jit_call_indirect( jit_call_cb: jitCallCb, }, m: { - h: (Module).asm.memory + h: (Module).getMemory() }, }); const impl = instance.exports.do_jit_call_indirect; diff --git a/src/mono/wasm/runtime/jiterpreter-support.ts b/src/mono/wasm/runtime/jiterpreter-support.ts index 5ce5759b2a6a4b..0589c28d5bd06e 100644 --- a/src/mono/wasm/runtime/jiterpreter-support.ts +++ b/src/mono/wasm/runtime/jiterpreter-support.ts @@ -239,9 +239,12 @@ export class WasmBuilder { } getWasmImports(): WebAssembly.Imports { + const memory = (Module).getMemory(); + mono_assert(memory instanceof WebAssembly.Memory, () => `expected heap import to be WebAssembly.Memory but was ${memory}`); + const result: any = { c: this.getConstants(), - m: { h: (Module).asm.memory }, + m: { h: memory }, // f: { f: getWasmFunctionTable() }, }; @@ -1589,7 +1592,7 @@ export function copyIntoScratchBuffer(src: NativePointer, size: number): NativeP export function getWasmFunctionTable() { if (!wasmTable) - wasmTable = (Module)["asm"]["__indirect_function_table"]; + wasmTable = Module.getWasmIndirectFunctionTable(); if (!wasmTable) throw new Error("Module did not export the indirect function table"); return wasmTable; diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts index aedf803aceff1f..a91b21973c8d5e 100644 --- a/src/mono/wasm/runtime/types/internal.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -454,6 +454,8 @@ export declare interface EmscriptenModuleInternal { ready: Promise; asm: { memory?: WebAssembly.Memory }; wasmMemory?: WebAssembly.Memory; + getWasmIndirectFunctionTable: any; + getMemory: WebAssembly.Memory; getWasmTableEntry(index: number): any; removeRunDependency(id: string): void; addRunDependency(id: string): void; diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 66bc509910571a..3b75fa9feeb1f0 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -33,7 +33,6 @@ <_EmccDefaultsRspPath>$(NativeBinDir)src\emcc-default.rsp <_EmccCompileRspPath>$(NativeBinDir)src\emcc-compile.rsp <_EmccLinkRspPath>$(NativeBinDir)src\emcc-link.rsp - false $(EMSDK_PATH)\upstream\bin\llvm-ar $(EmSdkLLVMAr).exe From 8c682063553fc744be2b2dfa82d131d03f8b6b23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 03:13:09 -0700 Subject: [PATCH 322/345] [release/8.0] JIT: Fixed containment of STOREIND of HW intrinsics ConvertTo*/Extract* (#92513) * Added OperIsHWIntrinsicSIMDScalar. Do not remove CAST on SIMD scalar operations for stores. * Minor cleanup * Minor cleanup * Feedback * Added test case * Update Runtime_92349.cs * Update Runtime_92349.cs * Update Runtime_92349.cs * Update Runtime_92349.cs * JIT: Fix containment of extract intrinsics as STOREIND sources Fix #92590 --------- Co-authored-by: TIHan Co-authored-by: Jakob Botsch Nielsen --- src/coreclr/jit/lowerxarch.cpp | 5 +- .../JitBlue/Runtime_92349/Runtime_92349.cs | 29 +++++++++ .../Runtime_92349/Runtime_92349.csproj | 9 +++ .../JitBlue/Runtime_92590/Runtime_92590.cs | 63 +++++++++++++++++++ .../Runtime_92590/Runtime_92590.csproj | 8 +++ 5 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.csproj create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.csproj diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 319238aaec628f..150ad04a55d99f 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -6504,7 +6504,7 @@ void Lowering::ContainCheckStoreIndir(GenTreeStoreInd* node) case NI_AVX2_ConvertToUInt32: { // These intrinsics are "ins reg/mem, xmm" - isContainable = varTypeIsIntegral(simdBaseType); + isContainable = varTypeIsIntegral(simdBaseType) && (genTypeSize(src) == genTypeSize(node)); break; } @@ -6568,7 +6568,8 @@ void Lowering::ContainCheckStoreIndir(GenTreeStoreInd* node) size_t numArgs = hwintrinsic->GetOperandCount(); GenTree* lastOp = hwintrinsic->Op(numArgs); - isContainable = HWIntrinsicInfo::isImmOp(intrinsicId, lastOp) && lastOp->IsCnsIntOrI(); + isContainable = HWIntrinsicInfo::isImmOp(intrinsicId, lastOp) && lastOp->IsCnsIntOrI() && + (genTypeSize(simdBaseType) == genTypeSize(node)); if (isContainable && (intrinsicId == NI_SSE2_Extract)) { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.cs b/src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.cs new file mode 100644 index 00000000000000..5de0a28895b268 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; +using System.Runtime.CompilerServices; +using System.Threading; +using Xunit; + +public static class Runtime_92349 +{ + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + unsafe static void Test(byte* pValue) + { + *pValue = (byte)Sse2.ConvertToInt32(Vector128.Create(-10, 0, 0, 0)); + } + + [Fact] + public unsafe static void EntryPoint() + { + if (Sse2.IsSupported) + { + ulong value = 0; + Test((byte*)Unsafe.AsPointer(ref value)); + Assert.True(value == 246); + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.csproj new file mode 100644 index 00000000000000..6bb210527e0797 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92349/Runtime_92349.csproj @@ -0,0 +1,9 @@ + + + True + True + + + + + \ No newline at end of file diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.cs b/src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.cs new file mode 100644 index 00000000000000..99a5ef2ee5d18d --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using Xunit; + +public class Runtime_92590 +{ + [Fact] + public static void TestEntryPoint() + { + Span bytes = stackalloc byte[4]; + bytes.Fill(0xff); + TestByteByte(ref bytes[0], 0, Vector256.Create((byte)1)); + + Assert.True(bytes.SequenceEqual(stackalloc byte[] { 0x2, 0xff, 0xff, 0xff })); + + bytes.Fill(0xff); + TestByteInt(ref bytes[0], 0, Vector256.Create(1)); + + Assert.True(bytes.SequenceEqual(stackalloc byte[] { 0x2, 0xff, 0xff, 0xff })); + + int i = int.MaxValue; + TestIntByte(ref i, 0, Vector256.Create((byte)1)); + + Assert.Equal(2, i); + + i = int.MaxValue; + TestIntInt(ref i, 0, Vector256.Create(1)); + + Assert.Equal(2, i); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void TestByteByte(ref byte b, int x, Vector256 vin) + { + Vector256 v = vin + vin; + Unsafe.Add(ref b, x) = v[3]; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void TestByteInt(ref byte b, int x, Vector256 vin) + { + Vector256 v = vin + vin; + Unsafe.Add(ref b, x) = (byte)v[3]; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void TestIntByte(ref int b, int x, Vector256 vin) + { + Vector256 v = vin + vin; + Unsafe.Add(ref b, x) = v[3]; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void TestIntInt(ref int b, int x, Vector256 vin) + { + Vector256 v = vin + vin; + Unsafe.Add(ref b, x) = v[3]; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.csproj new file mode 100644 index 00000000000000..15edd99711a1a4 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_92590/Runtime_92590.csproj @@ -0,0 +1,8 @@ + + + True + + + + + \ No newline at end of file From 7027ff1a3090fd901495d94ef73708ce08747c5c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 03:13:21 -0700 Subject: [PATCH 323/345] define bool as Interop.BOOL to prevent upper bytes setting native bool (#92681) Co-authored-by: yowl --- .../Runtime.Base/src/System/Runtime/InternalCalls.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index 3c9d6c86ffc323..5c11243bbad99b 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -62,12 +62,12 @@ internal static class InternalCalls [RuntimeExport("RhCollect")] internal static void RhCollect(int generation, InternalGCCollectionMode mode, bool lowMemoryP = false) { - RhpCollect(generation, mode, lowMemoryP); + RhpCollect(generation, mode, lowMemoryP ? Interop.BOOL.TRUE : Interop.BOOL.FALSE); } [DllImport(Redhawk.BaseName)] [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvCdecl) })] - private static extern void RhpCollect(int generation, InternalGCCollectionMode mode, bool lowMemoryP); + private static extern void RhpCollect(int generation, InternalGCCollectionMode mode, Interop.BOOL lowMemoryP); [RuntimeExport("RhGetGcTotalMemory")] internal static long RhGetGcTotalMemory() From 8c898a9350f66ee4dd1986249e33625a61d1bd71 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 09:27:17 -0700 Subject: [PATCH 324/345] [release/8.0] Make CoreCLR/NativeAOT assembly compile with .subsections_via_symbols on Apple platforms (#92544) * Make CoreCLR/NativeAOT assembly compile with .subsections_via_symbols on Apple platforms * Fix build with LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT --------- Co-authored-by: Filip Navara Co-authored-by: Jan Kotas --- .../nativeaot/Runtime/arm64/AllocFast.S | 30 +++++---- .../Runtime/arm64/ExceptionHandling.S | 66 +++++++++---------- src/coreclr/nativeaot/Runtime/arm64/GcProbe.S | 12 ++-- .../nativeaot/Runtime/arm64/WriteBarriers.S | 40 +++++------ .../nativeaot/Runtime/unix/unixasmmacros.inc | 5 ++ src/coreclr/pal/inc/unixasmmacros.inc | 5 ++ src/coreclr/vm/arm64/asmhelpers.S | 4 +- 7 files changed, 92 insertions(+), 70 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/arm64/AllocFast.S b/src/coreclr/nativeaot/Runtime/arm64/AllocFast.S index 2bab323e65abca..79ffed2b05210d 100644 --- a/src/coreclr/nativeaot/Runtime/arm64/AllocFast.S +++ b/src/coreclr/nativeaot/Runtime/arm64/AllocFast.S @@ -46,7 +46,7 @@ OFFSETOF__Thread__m_alloc_context__alloc_limit = OFFSETOF__Thread__m_rgbAll add x2, x2, x12 ldr x13, [x1, #OFFSETOF__Thread__m_alloc_context__alloc_limit] cmp x2, x13 - bhi RhpNewFast_RarePath + bhi LOCAL_LABEL(RhpNewFast_RarePath) // Update the alloc pointer to account for the allocation. str x2, [x1, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] @@ -57,7 +57,7 @@ OFFSETOF__Thread__m_alloc_context__alloc_limit = OFFSETOF__Thread__m_rgbAll mov x0, x12 ret -RhpNewFast_RarePath: +LOCAL_LABEL(RhpNewFast_RarePath): mov x1, #0 b C_FUNC(RhpNewObject) LEAF_END RhpNewFast, _TEXT @@ -88,12 +88,12 @@ RhpNewFast_RarePath: bl C_FUNC(RhpGcAlloc) // Set the new objects MethodTable pointer on success. - cbz x0, NewOutOfMemory + cbz x0, LOCAL_LABEL(NewOutOfMemory) POP_COOP_PINVOKE_FRAME EPILOG_RETURN -NewOutOfMemory: +LOCAL_LABEL(NewOutOfMemory): // This is the OOM failure path. We are going to tail-call to a managed helper that will throw // an out of memory exception that the caller of this allocator understands. @@ -113,7 +113,7 @@ NewOutOfMemory: movz x2, MAX_STRING_LENGTH & 0xFFFF movk x2, MAX_STRING_LENGTH >> 16, lsl 16 cmp x1, x2 - bhi StringSizeOverflow + bhi LOCAL_LABEL(StringSizeOverflow) // Compute overall allocation size (align(base size + (element size * elements), 8)). mov w2, #STRING_COMPONENT_SIZE @@ -139,7 +139,7 @@ NewOutOfMemory: add x2, x2, x12 ldr x12, [x3, #OFFSETOF__Thread__m_alloc_context__alloc_limit] cmp x2, x12 - bhi C_FUNC(RhpNewArrayRare) + bhi LOCAL_LABEL(RhNewString_Rare) // Reload new object address into r12. ldr x12, [x3, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] @@ -156,7 +156,7 @@ NewOutOfMemory: ret -StringSizeOverflow: +LOCAL_LABEL(StringSizeOverflow): // We get here if the length of the final string object can not be represented as an unsigned // 32-bit value. We are going to tail-call to a managed helper that will throw // an OOM exception that the caller of this allocator understands. @@ -164,6 +164,9 @@ StringSizeOverflow: // x0 holds MethodTable pointer already mov x1, #1 // Indicate that we should throw OverflowException b C_FUNC(RhExceptionHandling_FailedAllocation) + +LOCAL_LABEL(RhNewString_Rare): + b C_FUNC(RhpNewArrayRare) LEAF_END RhNewString, _Text // Allocate one dimensional, zero based array (SZARRAY). @@ -177,7 +180,7 @@ StringSizeOverflow: // case (32 dimensional MdArray) is less than 0xffff, and thus the product fits in 64 bits. mov x2, #0x7FFFFFFF cmp x1, x2 - bhi ArraySizeOverflow + bhi LOCAL_LABEL(ArraySizeOverflow) ldrh w2, [x0, #OFFSETOF__MethodTable__m_usComponentSize] umull x2, w1, w2 @@ -204,7 +207,7 @@ StringSizeOverflow: add x2, x2, x12 ldr x12, [x3, #OFFSETOF__Thread__m_alloc_context__alloc_limit] cmp x2, x12 - bhi C_FUNC(RhpNewArrayRare) + bhi LOCAL_LABEL(RhpNewArray_Rare) // Reload new object address into x12. ldr x12, [x3, #OFFSETOF__Thread__m_alloc_context__alloc_ptr] @@ -221,7 +224,7 @@ StringSizeOverflow: ret -ArraySizeOverflow: +LOCAL_LABEL(ArraySizeOverflow): // We get here if the size of the final array object can not be represented as an unsigned // 32-bit value. We are going to tail-call to a managed helper that will throw // an overflow exception that the caller of this allocator understands. @@ -229,6 +232,9 @@ ArraySizeOverflow: // x0 holds MethodTable pointer already mov x1, #1 // Indicate that we should throw OverflowException b C_FUNC(RhExceptionHandling_FailedAllocation) + +LOCAL_LABEL(RhpNewArray_Rare): + b C_FUNC(RhpNewArrayRare) LEAF_END RhpNewArray, _TEXT // Allocate one dimensional, zero based array (SZARRAY) using the slow path that calls a runtime helper. @@ -254,12 +260,12 @@ ArraySizeOverflow: bl C_FUNC(RhpGcAlloc) // Set the new objects MethodTable pointer and length on success. - cbz x0, ArrayOutOfMemory + cbz x0, LOCAL_LABEL(ArrayOutOfMemory) POP_COOP_PINVOKE_FRAME EPILOG_RETURN -ArrayOutOfMemory: +LOCAL_LABEL(ArrayOutOfMemory): // This is the OOM failure path. We are going to tail-call to a managed helper that will throw // an out of memory exception that the caller of this allocator understands. diff --git a/src/coreclr/nativeaot/Runtime/arm64/ExceptionHandling.S b/src/coreclr/nativeaot/Runtime/arm64/ExceptionHandling.S index d0425171e1d191..7c04f15ad3b858 100644 --- a/src/coreclr/nativeaot/Runtime/arm64/ExceptionHandling.S +++ b/src/coreclr/nativeaot/Runtime/arm64/ExceptionHandling.S @@ -275,7 +275,7 @@ // where the tail-calling thread had saved LR, which may not match where we have saved LR. ldr x1, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress] - cbz x1, NotHijacked + cbz x1, LOCAL_LABEL(NotHijacked) ldr x3, [x2, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation] @@ -286,13 +286,13 @@ add x12, sp, #(STACKSIZEOF_ExInfo + SIZEOF__PAL_LIMITED_CONTEXT) // re-compute SP at callsite cmp x3, x12 // if (m_ppvHijackedReturnAddressLocation < SP at callsite) - blo TailCallWasHijacked + blo LOCAL_LABEL(TailCallWasHijacked) // normal case where a valid return address location is hijacked str x1, [x3] - b ClearThreadState + b LOCAL_LABEL(ClearThreadState) -TailCallWasHijacked: +LOCAL_LABEL(TailCallWasHijacked): // Abnormal case where the return address location is now invalid because we ended up here via a tail // call. In this case, our hijacked return address should be the correct caller of this method. @@ -302,13 +302,13 @@ TailCallWasHijacked: str lr, [sp, #(rsp_offsetof_Context + OFFSETOF__PAL_LIMITED_CONTEXT__LR)] str lr, [sp, #(rsp_offsetof_Context + OFFSETOF__PAL_LIMITED_CONTEXT__IP)] -ClearThreadState: +LOCAL_LABEL(ClearThreadState): // clear the Thread's hijack state str xzr, [x2, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation] str xzr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress] -NotHijacked: +LOCAL_LABEL(NotHijacked): add x1, sp, #rsp_offsetof_ExInfo // x1 <- ExInfo* str xzr, [x1, #OFFSETOF__ExInfo__m_exception] // pExInfo->m_exception = null @@ -429,13 +429,13 @@ NotHijacked: add x12, x5, #OFFSETOF__Thread__m_ThreadStateFlags -ClearRetry_Catch: +LOCAL_LABEL(ClearRetry_Catch): ldxr w4, [x12] bic w4, w4, #TSF_DoNotTriggerGc stxr w6, w4, [x12] - cbz w6, ClearSuccess_Catch - b ClearRetry_Catch -ClearSuccess_Catch: + cbz w6, LOCAL_LABEL(ClearSuccess_Catch) + b LOCAL_LABEL(ClearRetry_Catch) +LOCAL_LABEL(ClearSuccess_Catch): // // set preserved regs to the values expected by the funclet @@ -487,21 +487,21 @@ ClearSuccess_Catch: ldr x3, [sp, #rsp_offset_x3] // x3 <- current ExInfo* ldr x2, [x2, #OFFSETOF__REGDISPLAY__SP] // x2 <- resume SP value -PopExInfoLoop: +LOCAL_LABEL(PopExInfoLoop): ldr x3, [x3, #OFFSETOF__ExInfo__m_pPrevExInfo] // x3 <- next ExInfo - cbz x3, DonePopping // if (pExInfo == null) { we're done } + cbz x3, LOCAL_LABEL(DonePopping) // if (pExInfo == null) { we're done } cmp x3, x2 - blt PopExInfoLoop // if (pExInfo < resume SP} { keep going } + blt LOCAL_LABEL(PopExInfoLoop) // if (pExInfo < resume SP} { keep going } -DonePopping: +LOCAL_LABEL(DonePopping): str x3, [x1, #OFFSETOF__Thread__m_pExInfoStackHead] // store the new head on the Thread PREPARE_EXTERNAL_VAR_INDIRECT_W RhpTrapThreads, 3 - tbz x3, #TrapThreadsFlags_AbortInProgress_Bit, NoAbort + tbz x3, #TrapThreadsFlags_AbortInProgress_Bit, LOCAL_LABEL(NoAbort) ldr x3, [sp, #rsp_offset_is_not_handling_thread_abort] - cbnz x3, NoAbort + cbnz x3, LOCAL_LABEL(NoAbort) // It was the ThreadAbortException, so rethrow it // reset SP @@ -510,7 +510,7 @@ DonePopping: mov sp, x2 b C_FUNC(RhpThrowHwEx) -NoAbort: +LOCAL_LABEL(NoAbort): // reset SP and jump to continuation address mov sp, x2 br x0 @@ -564,13 +564,13 @@ NoAbort: add x12, x2, #OFFSETOF__Thread__m_ThreadStateFlags -ClearRetry: +LOCAL_LABEL(ClearRetry): ldxr w4, [x12] bic w4, w4, #TSF_DoNotTriggerGc stxr w3, w4, [x12] - cbz w3, ClearSuccess - b ClearRetry -ClearSuccess: + cbz w3, LOCAL_LABEL(ClearSuccess) + b LOCAL_LABEL(ClearRetry) +LOCAL_LABEL(ClearSuccess): // // set preserved regs to the values expected by the funclet @@ -602,13 +602,13 @@ ClearSuccess: ldr x2, [sp, rsp_FinallyFunclet_offset_thread] add x12, x2, #OFFSETOF__Thread__m_ThreadStateFlags -SetRetry: +LOCAL_LABEL(SetRetry): ldxr w1, [x12] orr w1, w1, #TSF_DoNotTriggerGc stxr w3, w1, [x12] - cbz w3, SetSuccess - b SetRetry -SetSuccess: + cbz w3, LOCAL_LABEL(SetSuccess) + b LOCAL_LABEL(SetRetry) +LOCAL_LABEL(SetSuccess): ldp d8, d9, [sp, #0x00] ldp d10, d11, [sp, #0x10] @@ -707,13 +707,13 @@ SetSuccess: add x12, x5, #OFFSETOF__Thread__m_ThreadStateFlags -ClearRetry_Propagate: +LOCAL_LABEL(ClearRetry_Propagate): ldxr w4, [x12] bic w4, w4, #TSF_DoNotTriggerGc stxr w6, w4, [x12] - cbz w6, ClearSuccess_Propagate - b ClearRetry_Propagate -ClearSuccess_Propagate: + cbz w6, LOCAL_LABEL(ClearSuccess_Propagate) + b LOCAL_LABEL(ClearRetry_Propagate) +LOCAL_LABEL(ClearSuccess_Propagate): // // set preserved regs to the values expected by the funclet @@ -749,13 +749,13 @@ ClearSuccess_Propagate: ldr x3, [sp, #rsp_offset_x3] // x3 <- current ExInfo* ldr x2, [x2, #OFFSETOF__REGDISPLAY__SP] // x2 <- resume SP value -Propagate_PopExInfoLoop: +LOCAL_LABEL(Propagate_PopExInfoLoop): ldr x3, [x3, #OFFSETOF__ExInfo__m_pPrevExInfo] // x3 <- next ExInfo - cbz x3, Propagate_DonePopping // if (pExInfo == null) { we're done } + cbz x3, LOCAL_LABEL(Propagate_DonePopping) // if (pExInfo == null) { we're done } cmp x3, x2 - blt Propagate_PopExInfoLoop // if (pExInfo < resume SP} { keep going } + blt LOCAL_LABEL(Propagate_PopExInfoLoop) // if (pExInfo < resume SP} { keep going } -Propagate_DonePopping: +LOCAL_LABEL(Propagate_DonePopping): str x3, [x1, #OFFSETOF__Thread__m_pExInfoStackHead] // store the new head on the Thread // restore preemptive mode diff --git a/src/coreclr/nativeaot/Runtime/arm64/GcProbe.S b/src/coreclr/nativeaot/Runtime/arm64/GcProbe.S index e27834bae6fedd..abe7555b761134 100644 --- a/src/coreclr/nativeaot/Runtime/arm64/GcProbe.S +++ b/src/coreclr/nativeaot/Runtime/arm64/GcProbe.S @@ -127,10 +127,10 @@ NESTED_ENTRY RhpGcProbeHijack, _TEXT, NoHandler FixupHijackedCallstack PREPARE_EXTERNAL_VAR_INDIRECT_W RhpTrapThreads, 3 - tbnz x3, #TrapThreadsFlags_TrapThreads_Bit, WaitForGC + tbnz x3, #TrapThreadsFlags_TrapThreads_Bit, LOCAL_LABEL(WaitForGC) ret -WaitForGC: +LOCAL_LABEL(WaitForGC): orr x12, x12, DEFAULT_FRAME_SAVE_FLAGS + PTFF_SAVE_X0 + PTFF_SAVE_X1 b C_FUNC(RhpWaitForGC) NESTED_END RhpGcProbeHijack @@ -144,11 +144,11 @@ NESTED_ENTRY RhpWaitForGC, _TEXT, NoHandler bl C_FUNC(RhpWaitForGC2) ldr x2, [sp, #OFFSETOF__PInvokeTransitionFrame__m_Flags] - tbnz x2, #PTFF_THREAD_ABORT_BIT, ThrowThreadAbort + tbnz x2, #PTFF_THREAD_ABORT_BIT, LOCAL_LABEL(ThrowThreadAbort) POP_PROBE_FRAME EPILOG_RETURN -ThrowThreadAbort: +LOCAL_LABEL(ThrowThreadAbort): POP_PROBE_FRAME mov w0, #STATUS_REDHAWK_THREAD_ABORT mov x1, lr // return address as exception PC @@ -159,8 +159,10 @@ NESTED_END RhpWaitForGC LEAF_ENTRY RhpGcPoll PREPARE_EXTERNAL_VAR_INDIRECT_W RhpTrapThreads, 0 - cbnz w0, C_FUNC(RhpGcPollRare) // TrapThreadsFlags_None = 0 + cbnz w0, LOCAL_LABEL(RhpGcPoll_Rare) // TrapThreadsFlags_None = 0 ret +LOCAL_LABEL(RhpGcPoll_Rare): + b C_FUNC(RhpGcPollRare) LEAF_END RhpGcPoll NESTED_ENTRY RhpGcPollRare, _TEXT, NoHandler diff --git a/src/coreclr/nativeaot/Runtime/arm64/WriteBarriers.S b/src/coreclr/nativeaot/Runtime/arm64/WriteBarriers.S index d00ffb3a4a9978..835466c3b9e7e4 100644 --- a/src/coreclr/nativeaot/Runtime/arm64/WriteBarriers.S +++ b/src/coreclr/nativeaot/Runtime/arm64/WriteBarriers.S @@ -224,9 +224,11 @@ LEAF_END RhpByRefAssignRefArm64, _TEXT PREPARE_EXTERNAL_VAR_INDIRECT g_highest_address, x12 ccmp x14, x12, #0x2, hs - blo C_FUNC(RhpAssignRefArm64) + bhs LOCAL_LABEL(NotInHeap) -NotInHeap: + b C_FUNC(RhpAssignRefArm64) + +LOCAL_LABEL(NotInHeap): ALTERNATE_ENTRY RhpCheckedAssignRefAVLocation str x15, [x14], 8 ret @@ -293,44 +295,44 @@ LEAF_END RhpAssignRef, _TEXT #ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT PREPARE_EXTERNAL_VAR_INDIRECT_W g_cpuFeatures, 16 - tbz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, CmpXchgRetry + tbz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, LOCAL_LABEL(CmpXchgRetry) #endif mov x10, x2 ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation casal x10, x1, [x0] // exchange cmp x2, x10 - bne CmpXchgNoUpdate + bne LOCAL_LABEL(CmpXchgNoUpdate) #ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT - b DoCardsCmpXchg -CmpXchgRetry: + b LOCAL_LABEL(DoCardsCmpXchg) +LOCAL_LABEL(CmpXchgRetry): // Check location value is what we expect. ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation2 ldaxr x10, [x0] cmp x10, x2 - bne CmpXchgNoUpdate + bne LOCAL_LABEL(CmpXchgNoUpdate) // Current value matches comparand, attempt to update with the new value. stlxr w12, x1, [x0] - cbnz w12, CmpXchgRetry + cbnz w12, LOCAL_LABEL(CmpXchgRetry) #endif -DoCardsCmpXchg: +LOCAL_LABEL(DoCardsCmpXchg): // We have successfully updated the value of the objectref so now we need a GC write barrier. // The following barrier code takes the destination in x0 and the value in x1 so the arguments are // already correctly set up. INSERT_CHECKED_WRITE_BARRIER_CORE x0, x1 -CmpXchgNoUpdate: +LOCAL_LABEL(CmpXchgNoUpdate): // x10 still contains the original value. mov x0, x10 #ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT - tbnz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, NoBarrierCmpXchg + tbnz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, LOCAL_LABEL(NoBarrierCmpXchg) InterlockedOperationBarrier -NoBarrierCmpXchg: +LOCAL_LABEL(NoBarrierCmpXchg): #endif ret lr @@ -357,25 +359,25 @@ NoBarrierCmpXchg: #ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT PREPARE_EXTERNAL_VAR_INDIRECT_W g_cpuFeatures, 16 - tbz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, ExchangeRetry + tbz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, LOCAL_LABEL(ExchangeRetry) #endif ALTERNATE_ENTRY RhpCheckedXchgAVLocation swpal x1, x10, [x0] // exchange #ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT - b DoCardsXchg -ExchangeRetry: + b LOCAL_LABEL(DoCardsXchg) +LOCAL_LABEL(ExchangeRetry): // Read the existing memory location. ALTERNATE_ENTRY RhpCheckedXchgAVLocation2 ldaxr x10, [x0] // Attempt to update with the new value. stlxr w12, x1, [x0] - cbnz w12, ExchangeRetry + cbnz w12, LOCAL_LABEL(ExchangeRetry) #endif -DoCardsXchg: +LOCAL_LABEL(DoCardsXchg): // We have successfully updated the value of the objectref so now we need a GC write barrier. // The following barrier code takes the destination in x0 and the value in x1 so the arguments are // already correctly set up. @@ -386,9 +388,9 @@ DoCardsXchg: mov x0, x10 #ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT - tbnz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, NoBarrierXchg + tbnz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, LOCAL_LABEL(NoBarrierXchg) InterlockedOperationBarrier -NoBarrierXchg: +LOCAL_LABEL(NoBarrierXchg): #endif ret diff --git a/src/coreclr/nativeaot/Runtime/unix/unixasmmacros.inc b/src/coreclr/nativeaot/Runtime/unix/unixasmmacros.inc index ef6d393fd248b1..bde1d517b7e823 100644 --- a/src/coreclr/nativeaot/Runtime/unix/unixasmmacros.inc +++ b/src/coreclr/nativeaot/Runtime/unix/unixasmmacros.inc @@ -3,6 +3,11 @@ #define INVALIDGCVALUE 0xCCCCCCCD +// Enforce subsections via symbols to workaround bugs in Xcode 15 linker. +#if defined(__APPLE__) +.subsections_via_symbols +#endif + #if defined(__APPLE__) #define C_FUNC(name) _##name #define EXTERNAL_C_FUNC(name) C_FUNC(name) diff --git a/src/coreclr/pal/inc/unixasmmacros.inc b/src/coreclr/pal/inc/unixasmmacros.inc index 658a65bb4b35aa..120b26543e3faa 100644 --- a/src/coreclr/pal/inc/unixasmmacros.inc +++ b/src/coreclr/pal/inc/unixasmmacros.inc @@ -3,6 +3,11 @@ #define INVALIDGCVALUE 0xCCCCCCCD +// Enforce subsections via symbols to workaround bugs in Xcode 15 linker. +#if defined(__APPLE__) +.subsections_via_symbols +#endif + #if defined(__APPLE__) #define C_FUNC(name) _##name #define EXTERNAL_C_FUNC(name) C_FUNC(name) diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index cdbe24ec427a98..89dab80461c356 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -329,7 +329,9 @@ WRITE_BARRIER_ENTRY JIT_CheckedWriteBarrier // branch below is not taken. ccmp x14, x12, #0x2, hs - blo C_FUNC(JIT_WriteBarrier) + bhs LOCAL_LABEL(NotInHeap) + + b C_FUNC(JIT_WriteBarrier) LOCAL_LABEL(NotInHeap): str x15, [x14], 8 From 56749c5b8dac62e96cba794499f363ab310f3530 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:13:53 -0700 Subject: [PATCH 325/345] [release/8.0] Fix LLVMAOT Mono runtime variant official build to produce correctly named runtime packs (#92737) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix LLVMAOT Mono runtime variant official build to produce correctly named runtime packs In https://github.com/dotnet/runtime/commit/75ee623b8f0350a4b4be86fa71745a74beb059d1 the condition in src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.props got changed from checking `MonoBundleLLVMOptimizer` to `MonoAOTEnableLLVM` but we weren't setting that property in runtime-official.yml so both jobs produced runtime packs with the same suffix, resulting in the artifact uploads randomly overwriting each other. * Fix more places that need MonoAOTEnableLLVM=true --------- Co-authored-by: Alexander Köplinger --- eng/pipelines/runtime-llvm.yml | 4 ++-- eng/pipelines/runtime-official.yml | 2 +- eng/pipelines/runtime.yml | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/pipelines/runtime-llvm.yml b/eng/pipelines/runtime-llvm.yml index e31e623a0353c8..9d358e5f793086 100644 --- a/eng/pipelines/runtime-llvm.yml +++ b/eng/pipelines/runtime-llvm.yml @@ -119,7 +119,7 @@ extends: testGroup: innerloop nameSuffix: AllSubsets_Mono_LLVMAOT buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) - /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + /p:MonoEnableLLVM=true /p:MonoAOTEnableLLVM=true /p:MonoBundleLLVMOptimizer=true condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), @@ -138,7 +138,7 @@ extends: testGroup: innerloop nameSuffix: AllSubsets_Mono_LLVMAOT buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) - /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + /p:MonoEnableLLVM=true /p:MonoAOTEnableLLVM=true /p:MonoBundleLLVMOptimizer=true condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 9c341a04791289..3a9fd8d89ac4b0 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -334,7 +334,7 @@ extends: runtimeFlavor: mono jobParameters: buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) - /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + /p:MonoEnableLLVM=true /p:MonoAOTEnableLLVM=true /p:MonoBundleLLVMOptimizer=true nameSuffix: AllSubsets_Mono_LLVMAOT runtimeVariant: LLVMAOT isOfficialBuild: ${{ variables.isOfficialBuild }} diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 050fc9037db965..3aa0b6504819a7 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -780,7 +780,7 @@ extends: testGroup: innerloop nameSuffix: AllSubsets_Mono_LLVMAOT buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) - /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + /p:MonoEnableLLVM=true /p:MonoAOTEnableLLVM=true /p:MonoBundleLLVMOptimizer=true condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), @@ -799,7 +799,7 @@ extends: testGroup: innerloop nameSuffix: AllSubsets_Mono_LLVMAOT buildArgs: -s mono+libs+host+packs -c $(_BuildConfig) - /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + /p:MonoEnableLLVM=true /p:MonoAOTEnableLLVM=true /p:MonoBundleLLVMOptimizer=true condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true), @@ -1318,7 +1318,7 @@ extends: testGroup: innerloop nameSuffix: AllSubsets_Mono_LLVMAot_RuntimeTests runtimeVariant: llvmaot - buildArgs: -s mono+libs+clr.hosts+clr.iltools -c Release /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + buildArgs: -s mono+libs+clr.hosts+clr.iltools -c Release /p:MonoEnableLLVM=true /p:MonoAOTEnableLLVM=true /p:MonoBundleLLVMOptimizer=true timeoutInMinutes: 180 condition: >- From 885100b00bc944cbb698bc4cc2ec3ec18007534f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:14:48 -0700 Subject: [PATCH 326/345] [release/8.0] Remove all PGO assets except for the runtime PGO archive. (#92735) * Remove all PGO assets except for the runtime PGO archive. * Don't produce a NuGet package for the runtime pack when PGO instrumenting --------- Co-authored-by: Jeremy Koritzinsky Co-authored-by: Jeremy Koritzinsky --- eng/Subsets.props | 4 ++-- .../Microsoft.NETCore.App.Runtime.sfxproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index 77268ffa7b5d09..eb4151f3a185d6 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -502,7 +502,7 @@ - + @@ -512,7 +512,7 @@ - + diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj index ba597425bcfc1d..979432e74e5fa8 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj @@ -7,8 +7,8 @@ dotnet-runtime-internal dotnet-runtime dotnet-runtime-internal - $(SharedFrameworkName).PGO true + false dotnet-runtime-symbols NetCore.SharedFramework true From 29cdcc1a41a4ac00ec1a45f03e70fe95a23215d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 15:38:12 -0700 Subject: [PATCH 327/345] [release/8.0] Put HasNativeCodeReJITAware into GetFunctionAddress (#92665) * Put HasNativeCodeReJITAware into GetFunctionAddress * get rid of unused code * reverting GetFunctionAddress to previous behavior * removing if statement * clarify method names * add comments * use BreakpointData.codeStartAddress * dac cast * address code review * the method has not been jitted yet --------- Co-authored-by: Mikelle --- src/coreclr/debug/daccess/dacimpl.h | 11 ------ src/coreclr/debug/daccess/task.cpp | 4 +- src/coreclr/debug/di/breakpoint.cpp | 2 + src/coreclr/debug/ee/controller.cpp | 24 ++---------- src/coreclr/debug/ee/debugger.cpp | 56 ++++++--------------------- src/coreclr/debug/ee/debugger.h | 4 +- src/coreclr/debug/ee/functioninfo.cpp | 10 +---- src/coreclr/debug/inc/dbgipcevents.h | 1 + src/coreclr/vm/dbginterface.h | 7 +--- src/coreclr/vm/eedbginterfaceimpl.cpp | 1 - src/coreclr/vm/encee.cpp | 4 +- src/coreclr/vm/method.cpp | 19 +++++---- src/coreclr/vm/method.hpp | 8 ++-- 13 files changed, 41 insertions(+), 110 deletions(-) diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h index ddf61370f416e9..8de684a5dae9a2 100644 --- a/src/coreclr/debug/daccess/dacimpl.h +++ b/src/coreclr/debug/daccess/dacimpl.h @@ -1253,17 +1253,6 @@ class ClrDataAccess /* [out] */ union STUB_BUF* outBuffer, /* [out] */ ULONG32* outFlags); - DebuggerJitInfo* GetDebuggerJitInfo(MethodDesc* methodDesc, - TADDR addr) - { - if (g_pDebugger) - { - return g_pDebugger->GetJitInfo(methodDesc, (PBYTE)addr, NULL); - } - - return NULL; - } - HRESULT GetMethodExtents(MethodDesc* methodDesc, METH_EXTENTS** extents); HRESULT GetMethodVarInfo(MethodDesc* methodDesc, diff --git a/src/coreclr/debug/daccess/task.cpp b/src/coreclr/debug/daccess/task.cpp index 9e428e81adef2b..ddbf251b7b9825 100644 --- a/src/coreclr/debug/daccess/task.cpp +++ b/src/coreclr/debug/daccess/task.cpp @@ -5225,7 +5225,7 @@ EnumMethodInstances::Next(ClrDataAccess* dac, } } - if (!m_methodIter.Current()->HasNativeCodeReJITAware()) + if (!m_methodIter.Current()->HasNativeCodeAnyVersion()) { goto NextMethod; } @@ -5243,7 +5243,7 @@ EnumMethodInstances::CdStart(MethodDesc* methodDesc, CLRDATA_ENUM* handle) { if (!methodDesc->HasClassOrMethodInstantiation() && - !methodDesc->HasNativeCodeReJITAware()) + !(methodDesc->HasNativeCodeAnyVersion())) { *handle = 0; return S_FALSE; diff --git a/src/coreclr/debug/di/breakpoint.cpp b/src/coreclr/debug/di/breakpoint.cpp index ad45df5c618ace..568d7fc9fc66ad 100644 --- a/src/coreclr/debug/di/breakpoint.cpp +++ b/src/coreclr/debug/di/breakpoint.cpp @@ -211,11 +211,13 @@ HRESULT CordbFunctionBreakpoint::Activate(BOOL fActivate) if (codeIsIL) { pEvent->BreakpointData.nativeCodeMethodDescToken = pEvent->BreakpointData.nativeCodeMethodDescToken.NullPtr(); + pEvent->BreakpointData.codeStartAddress = 0; } else { pEvent->BreakpointData.nativeCodeMethodDescToken = (m_code.GetValue()->AsNativeCode())->GetVMNativeCodeMethodDescToken().ToLsPtr(); + pEvent->BreakpointData.codeStartAddress = (m_code.GetValue()->AsNativeCode())->GetAddress(); } // Note: we're sending a two-way event, so it blocks here diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 7dd186b4113d44..58e63ab399db2c 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -1247,26 +1247,8 @@ bool DebuggerController::BindPatch(DebuggerControllerPatch *patch, startAddr = (CORDB_ADDRESS_TYPE *) CORDB_ADDRESS_TO_PTR(patch->GetDJI()->m_addrOfCode); _ASSERTE(startAddr != NULL); } - if (startAddr == NULL) - { - // Should not be trying to place patches on MethodDecs's for stubs. - // These stubs will never get jitted. - CONSISTENCY_CHECK_MSGF(!pMD->IsWrapperStub(), ("Can't place patch at stub md %p, %s::%s", - pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName)); - - startAddr = (CORDB_ADDRESS_TYPE *)g_pEEInterface->GetFunctionAddress(pMD); - // - // Code is not available yet to patch. The prestub should - // notify us when it is executed. - // - if (startAddr == NULL) - { - LOG((LF_CORDB, LL_INFO10000, - "DC::BP: Patch at 0x%zx not bindable yet.\n", patch->offset)); - - return false; - } - } + //We should never be calling this function with both a NULL startAddr and a DJI that doesn't have code. + _ASSERTE(startAddr != NULL); } _ASSERTE(!g_pEEInterface->IsStub((const BYTE *)startAddr)); @@ -8656,7 +8638,7 @@ bool DebuggerFuncEvalComplete::SendEvent(Thread *thread, bool fIpChanged) // DebuggerEnCBreakpoint constructor - creates and activates a new EnC breakpoint // // Arguments: -// offset - native offset in the function to place the patch +// offset - IL offset in the function to place the patch // jitInfo - identifies the function in which the breakpoint is being placed // fTriggerType - breakpoint type: either REMAP_PENDING or REMAP_COMPLETE // pAppDomain - the breakpoint applies to the specified AppDomain only diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index a44a9e235f36cd..d58a987244a8ea 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -2841,6 +2841,8 @@ HRESULT Debugger::GetILToNativeMapping(PCODE pNativeCodeStartAddress, ULONG32 cM } CONTRACTL_END; + _ASSERTE(pNativeCodeStartAddress != NULL); + #ifdef PROFILING_SUPPORTED // At this point, we're pulling in the debugger. if (!HasLazyData()) @@ -3007,6 +3009,7 @@ HRESULT Debugger::GetILToNativeMappingIntoArrays( _ASSERTE(pcMap != NULL); _ASSERTE(prguiILOffset != NULL); _ASSERTE(prguiNativeOffset != NULL); + _ASSERTE(pNativeCodeStartAddress != NULL); // Any caller of GetILToNativeMappingIntoArrays had better call // InitializeLazyDataIfNecessary first! @@ -5411,28 +5414,6 @@ void Debugger::ReleaseAllRuntimeThreads(AppDomain *pAppDomain) g_pEEInterface->ResumeFromDebug(pAppDomain); } -// Given a method, get's its EnC version number. 1 if the method is not EnCed. -// Note that MethodDescs are reused between versions so this will give us -// the most recent EnC number. -int Debugger::GetMethodEncNumber(MethodDesc * pMethod) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END; - - DebuggerJitInfo * dji = GetLatestJitInfoFromMethodDesc(pMethod); - if (dji == NULL) - { - // If there's no DJI, couldn't have been EnCed. - return 1; - } - return (int) dji->m_encVersion; -} - - bool Debugger::IsJMCMethod(Module* pModule, mdMethodDef tkMethod) { CONTRACTL @@ -6219,25 +6200,6 @@ void Debugger::LockAndSendEnCRemapCompleteEvent(MethodDesc *pMD) Thread *thread = g_pEEInterface->GetThread(); // Note that the debugger lock is reentrant, so we may or may not hold it already. SENDIPCEVENT_BEGIN(this, thread); - - EX_TRY - { - // Ensure the DJI for the latest version of this method has been pre-created. - // It's not clear whether this is necessary or not, but it shouldn't hurt since - // we're going to need to create it anyway since we'll be debugging inside it. - DebuggerJitInfo *dji = g_pDebugger->GetLatestJitInfoFromMethodDesc(pMD); - (void)dji; //prevent "unused variable" error from GCC - _ASSERTE( dji != NULL ); - } - EX_CATCH - { - // GetLatestJitInfo could throw on OOM, but the debugger isn't resiliant to OOM. - // I'm not aware of any other legitimate reason why it may throw, so we'll ASSERT - // if it fails. - _ASSERTE(!"Unexpected exception from Debugger::GetLatestJitInfoFromMethodDesc on EnC remap complete"); - } - EX_END_CATCH(RethrowTerminalExceptions); - // Send an EnC remap complete event to the Right Side. DebuggerIPCEvent* ipce = m_pRCThread->GetIPCEventSendBuffer(); InitIPCEvent(ipce, @@ -7865,6 +7827,7 @@ void Debugger::FirstChanceManagedExceptionCatcherFound(Thread *pThread, // Implements DebugInterface // Call by EE/exception. Must be on managed thread _ASSERTE(GetThreadNULLOk() != NULL); + _ASSERTE(pMethodAddr != NULL); // Quick check. if (!CORDebuggerAttached()) @@ -10498,7 +10461,7 @@ bool Debugger::HandleIPCEvent(DebuggerIPCEvent * pEvent) DebuggerJitInfo * pDJI = NULL; if ((pMethodDesc != NULL) && (pDMI != NULL)) { - pDJI = pDMI->FindOrCreateInitAndAddJitInfo(pMethodDesc, NULL /* startAddr */); + pDJI = pDMI->FindOrCreateInitAndAddJitInfo(pMethodDesc, PINSTRToPCODE(dac_cast(pEvent->BreakpointData.codeStartAddress))); } { @@ -12625,7 +12588,7 @@ DWORD Debugger::GetThreadIdHelper(Thread *pThread) // does not own the memory provided via vars outparameter. //----------------------------------------------------------------------------- void Debugger::GetVarInfo(MethodDesc * fd, // [IN] method of interest - void *DebuggerVersionToken, // [IN] which edit version + CORDB_ADDRESS nativeCodeAddress, // [IN] which edit version SIZE_T * cVars, // [OUT] size of 'vars' const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored ) @@ -12637,7 +12600,7 @@ void Debugger::GetVarInfo(MethodDesc * fd, // [IN] method of interest } CONTRACTL_END; - DebuggerJitInfo * ji = (DebuggerJitInfo *)DebuggerVersionToken; + DebuggerJitInfo * ji = g_pDebugger->GetJitInfo(fd, (const BYTE *)nativeCodeAddress); // If we didn't supply a DJI, then we're asking for the most recent version. if (ji == NULL) @@ -12961,6 +12924,11 @@ HRESULT Debugger::UpdateFunction(MethodDesc* pMD, SIZE_T encVersion) // For each offset in the IL->Native map, set a new EnC breakpoint on the // ones that we know could be remap points. + + // Depending on which DJI was picked, the code might compute different IL offsets. The JIT may not guarantee it produces + // the same set of sequence points for every generic instantiation. + // Inside ENCSequencePointHelper there is logic that skips IL offsets that map to the same native offset. + // Its possible that one version of the code maps two IL offsets to the same native offset but another version of the code maps them to different offsets. PTR_DebuggerILToNativeMap seqMap = pJitInfo->GetSequenceMap(); for (unsigned int i = 0; i < pJitInfo->GetSequenceMapCount(); i++) { diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index 26edd26a96140b..2c2440ddaf6977 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -1933,8 +1933,6 @@ class Debugger : public DebugInterface bool IsJMCMethod(Module* pModule, mdMethodDef tkMethod); - int GetMethodEncNumber(MethodDesc * pMethod); - bool FirstChanceManagedException(Thread *pThread, SIZE_T currentIP, SIZE_T currentSP); @@ -1980,7 +1978,7 @@ class Debugger : public DebugInterface #endif // EnC_SUPPORTED void GetVarInfo(MethodDesc * fd, // [IN] method of interest - void *DebuggerVersionToken, // [IN] which edit version + CORDB_ADDRESS nativeCodeAddress, // [IN] which edit version SIZE_T * cVars, // [OUT] size of 'vars' const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored ); diff --git a/src/coreclr/debug/ee/functioninfo.cpp b/src/coreclr/debug/ee/functioninfo.cpp index 76d4be3ab232f2..6eaa02d2c6de6f 100644 --- a/src/coreclr/debug/ee/functioninfo.cpp +++ b/src/coreclr/debug/ee/functioninfo.cpp @@ -1565,9 +1565,7 @@ DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* f GC_NOTRIGGER; } CONTRACTL_END; - _ASSERTE(fd != NULL); - // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata. if (fd->IsDynamicMethod()) { @@ -1576,15 +1574,11 @@ DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* f if (startAddr == NULL) { - // This will grab the start address for the current code version. startAddr = g_pEEInterface->GetFunctionAddress(fd); if (startAddr == NULL) { - startAddr = fd->GetNativeCodeReJITAware(); - if (startAddr == NULL) - { - return NULL; - } + //The only case this should happen is if we are trying to get the DJI for a method that has not been jitted yet. + return NULL; } } else diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h index 9fe1afd31a54ba..e9643e50f480a2 100644 --- a/src/coreclr/debug/inc/dbgipcevents.h +++ b/src/coreclr/debug/inc/dbgipcevents.h @@ -2011,6 +2011,7 @@ struct MSLAYOUT DebuggerIPCEvent SIZE_T offset; SIZE_T encVersion; LSPTR_METHODDESC nativeCodeMethodDescToken; // points to the MethodDesc if !isIL + CORDB_ADDRESS codeStartAddress; } BreakpointData; struct MSLAYOUT diff --git a/src/coreclr/vm/dbginterface.h b/src/coreclr/vm/dbginterface.h index daa57d25c86cf3..85b9785bccbb9b 100644 --- a/src/coreclr/vm/dbginterface.h +++ b/src/coreclr/vm/dbginterface.h @@ -203,7 +203,7 @@ class DebugInterface // Get debugger variable information for a specific version of a method virtual void GetVarInfo(MethodDesc * fd, // [IN] method of interest - void *DebuggerVersionToken, // [IN] which edit version + CORDB_ADDRESS nativeCodeAddress, // [IN] which edit version SIZE_T * cVars, // [OUT] size of 'vars' const ICorDebugInfo::NativeVarInfo **vars // [OUT] map telling where local vars are stored ) = 0; @@ -262,11 +262,6 @@ class DebugInterface virtual bool IsJMCMethod(Module* pModule, mdMethodDef tkMethod) = 0; - // Given a method, get's its EnC version number. 1 if the method is not EnCed. - // Note that MethodDescs are reused between versions so this will give us - // the most recent EnC number. - virtual int GetMethodEncNumber(MethodDesc * pMethod) = 0; - virtual void SendLogSwitchSetting (int iLevel, int iReason, _In_z_ LPCWSTR pLogSwitchName, diff --git a/src/coreclr/vm/eedbginterfaceimpl.cpp b/src/coreclr/vm/eedbginterfaceimpl.cpp index 792c608918a61d..352a534d5c1a88 100644 --- a/src/coreclr/vm/eedbginterfaceimpl.cpp +++ b/src/coreclr/vm/eedbginterfaceimpl.cpp @@ -630,7 +630,6 @@ PCODE EEDbgInterfaceImpl::GetFunctionAddress(MethodDesc *pFD) SUPPORTS_DAC; } CONTRACTL_END; - return pFD->GetNativeCode(); } diff --git a/src/coreclr/vm/encee.cpp b/src/coreclr/vm/encee.cpp index 1dcfb8bf091f4c..3339462ad7fe77 100644 --- a/src/coreclr/vm/encee.cpp +++ b/src/coreclr/vm/encee.cpp @@ -806,8 +806,8 @@ NOINLINE void EditAndContinueModule::FixContextAndResume( // Get the var info which the codemanager will use for updating // enregistered variables correctly, or variables whose lifetimes differ // at the update point - g_pDebugInterface->GetVarInfo(pMD, oldDebuggerFuncHandle, &oldVarInfoCount, &pOldVarInfo); - g_pDebugInterface->GetVarInfo(pMD, NULL, &newVarInfoCount, &pNewVarInfo); + g_pDebugInterface->GetVarInfo(pMD, oldCodeInfo.GetCodeAddress(), &oldVarInfoCount, &pOldVarInfo); + g_pDebugInterface->GetVarInfo(pMD, newCodeInfo.GetCodeAddress(), &newVarInfoCount, &pNewVarInfo); #ifdef TARGET_X86 // save the frame pointer as FixContextForEnC might step on it. diff --git a/src/coreclr/vm/method.cpp b/src/coreclr/vm/method.cpp index 62b24e3dc091c6..29910d6cb4c1c3 100644 --- a/src/coreclr/vm/method.cpp +++ b/src/coreclr/vm/method.cpp @@ -913,7 +913,6 @@ PCODE MethodDesc::GetNativeCode() WRAPPER_NO_CONTRACT; SUPPORTS_DAC; _ASSERTE(!IsDefaultInterfaceMethod() || HasNativeCodeSlot()); - if (HasNativeCodeSlot()) { // When profiler is enabled, profiler may ask to rejit a code even though we @@ -935,7 +934,7 @@ PCODE MethodDesc::GetNativeCode() return GetStableEntryPoint(); } -PCODE MethodDesc::GetNativeCodeReJITAware() +PCODE MethodDesc::GetNativeCodeAnyVersion() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; @@ -946,19 +945,23 @@ PCODE MethodDesc::GetNativeCodeReJITAware() return pDefaultCode; } + else { CodeVersionManager *pCodeVersionManager = GetCodeVersionManager(); CodeVersionManager::LockHolder codeVersioningLockHolder; - ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(PTR_MethodDesc(this)); - if (!ilVersion.IsDefaultVersion()) + ILCodeVersionCollection ilVersionCollection = pCodeVersionManager->GetILCodeVersions(PTR_MethodDesc(this)); + for (ILCodeVersionIterator curIL = ilVersionCollection.Begin(), endIL = ilVersionCollection.End(); curIL != endIL; curIL++) { - NativeCodeVersion activeNativeCodeVersion = ilVersion.GetActiveNativeCodeVersion(PTR_MethodDesc(this)); - if (!activeNativeCodeVersion.IsNull()) + NativeCodeVersionCollection nativeCollection = curIL->GetNativeCodeVersions(PTR_MethodDesc(this)); + for (NativeCodeVersionIterator curNative = nativeCollection.Begin(), endNative = nativeCollection.End(); curNative != endNative; curNative++) { - return activeNativeCodeVersion.GetNativeCode(); + PCODE native = curNative->GetNativeCode(); + if(native != NULL) + { + return native; + } } } - return NULL; } } diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index e51d9f7453d35e..12b3c86e0f7414 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1373,11 +1373,11 @@ class MethodDesc } // Perf warning: takes the CodeVersionManagerLock on every call - BOOL HasNativeCodeReJITAware() + BOOL HasNativeCodeAnyVersion() { LIMITED_METHOD_DAC_CONTRACT; - return GetNativeCodeReJITAware() != NULL; + return GetNativeCodeAnyVersion() != NULL; } BOOL SetNativeCodeInterlocked(PCODE addr, PCODE pExpected = NULL); @@ -1437,9 +1437,9 @@ class MethodDesc PCODE GetNativeCode(); // Returns GetNativeCode() if it exists, but also checks to see if there - // is a non-default IL code version and returns that. + // is a non-default code version that is populated with a code body and returns that. // Perf warning: takes the CodeVersionManagerLock on every call - PCODE GetNativeCodeReJITAware(); + PCODE GetNativeCodeAnyVersion(); #if defined(FEATURE_JIT_PITCHING) bool IsPitchable(); From 65496c87aa24dd2c4929414f255aaed95b0c183b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 17:20:26 -0700 Subject: [PATCH 328/345] [release/8.0] Update dependencies from dotnet/cecil dotnet/emsdk (#92702) * Update dependencies from https://github.com/dotnet/cecil build 20230926.1 Microsoft.DotNet.Cecil From Version 0.11.4-alpha.23468.2 -> To Version 0.11.4-alpha.23476.1 * Update dependencies from https://github.com/dotnet/emsdk build 20230927.1 Microsoft.NET.Workload.Emscripten.Current.Manifest-8.0.100.Transport From Version 8.0.0-rtm.23475.3 -> To Version 8.0.0-rtm.23477.1 * [wasm] WBT: Update skiasharp reference `blz_deploy_on_build_Debug_True_npl3f0nk_qee.csproj : error NU1903: Package 'SkiaSharp' 2.88.4-preview.76 has a known high severity vulnerability` --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Ankit Jain --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a4ab920e969679..05b333df6f0a03 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -85,14 +85,14 @@ 02fe27cd6a9b001c8feb7938e6ef4b3799745759b - + https://github.com/dotnet/cecil - 89be445dd4936157533ad96bafb95f701430653a + 13d6536e2dc92404da76d61d248badc040eb0de0 - + https://github.com/dotnet/emsdk - 0a2aae889f5ce2803fa227e13963b3fbf3ccb6b0 + ae4eaab4a9415d7f87ca7c6dc0b41ea482fa6337 diff --git a/eng/Versions.props b/eng/Versions.props index 0a745db24ef032..d3895c15f20726 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -213,7 +213,7 @@ 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23468.2 + 0.11.4-alpha.23476.1 8.0.0-rc.1.23406.6 @@ -240,7 +240,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport --> - 8.0.0-rtm.23475.3 + 8.0.0-rtm.23477.1 $(MicrosoftNETWorkloadEmscriptenCurrentManifest80100TransportVersion) 1.1.87-gba258badda diff --git a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs index fa15c7bef6d817..9633d22701cf0d 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs @@ -588,8 +588,8 @@ internal BuildPaths GetBuildPaths(BuildArgs buildArgs, bool forPublish = true) } protected static string GetSkiaSharpReferenceItems() - => @" - + => @" + "; protected static string s_mainReturns42 = @" From 5ab27e3a38f76476a11bc4d7bb4ad4087699e204 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 27 Sep 2023 21:34:51 -0400 Subject: [PATCH 329/345] [wasm] WBT: Update skiasharp reference (#92747) `blz_deploy_on_build_Debug_True_npl3f0nk_qee.csproj : error NU1903: Package 'SkiaSharp' 2.88.4-preview.76 has a known high severity vulnerability` From 228f2a4132d5dd23309ba81a98f20f1d9e645d59 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Thu, 28 Sep 2023 16:53:01 -0400 Subject: [PATCH 330/345] Update dependencies from dotnet/installer (#92745) Updating 'Microsoft.Dotnet.Sdk.Internal': '8.0.100-rc.2.23470.7' => '8.0.100-rtm.23477.25' (from build '202309 27.25' of 'https://github.com/dotnet/installer') --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 05b333df6f0a03..03bccd20386b46 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -398,9 +398,9 @@ https://github.com/NuGet/NuGet.Client 8fef55f5a55a3b4f2c96cd1a9b5ddc51d4b927f8 - + https://github.com/dotnet/installer - dbeae1ac71d95355452952059f35960991cb3fd2 + 744d4d634443834750b5c10cc3029123a6fd975e diff --git a/eng/Versions.props b/eng/Versions.props index d3895c15f20726..ca343d399f9cec 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -258,7 +258,7 @@ 3.1.7 1.0.406601 - 8.0.100-rc.2.23470.7 + 8.0.100-rtm.23477.25 $(MicrosoftDotnetSdkInternalVersion) From 2227dc804850baee5cf5b10a6b58d22f2667740e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:58:38 -0700 Subject: [PATCH 331/345] [release/8.0] Bring back CopyOutputSymbolsToPublishDirectory (#92369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bring back CopyOutputSymbolsToPublishDirectory I accidentally removed this property from AOT compilation when adding support for Mac dsym bundles. This change re-enables support for suppressing debugging symbols in the output. Fixes #92188 * Update src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets Co-authored-by: Michal Strehovský --------- Co-authored-by: Andy Gocke Co-authored-by: Andy Gocke Co-authored-by: Michal Strehovský --- .../BuildIntegration/Microsoft.NETCore.Native.Publish.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets index caee0777b30ddd..da6c90642f6f13 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Publish.targets @@ -95,7 +95,10 @@ + + From 575ddd203c232a6bd6f1e3dc0a7aa13660094265 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Thu, 28 Sep 2023 20:59:07 -0400 Subject: [PATCH 332/345] Update dependencies from `dotnet/installer` (#92795) Updating 'Microsoft.Dotnet.Sdk.Internal': '8.0.100-rtm.23477.25' => '8.0.100-rtm.23478.7' (from build '20230928.7' of 'https://github.com/dotnet/installer') --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 03bccd20386b46..a9b02fff630165 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -398,9 +398,9 @@ https://github.com/NuGet/NuGet.Client 8fef55f5a55a3b4f2c96cd1a9b5ddc51d4b927f8 - + https://github.com/dotnet/installer - 744d4d634443834750b5c10cc3029123a6fd975e + 46a7370763921ded24dcb70c585ee97883c615d4 diff --git a/eng/Versions.props b/eng/Versions.props index ca343d399f9cec..ef222884b7cd94 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -258,7 +258,7 @@ 3.1.7 1.0.406601 - 8.0.100-rtm.23477.25 + 8.0.100-rtm.23478.7 $(MicrosoftDotnetSdkInternalVersion) From b20f704cc00f390e5560a137deb8f0e64e863e1d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:17:11 -0700 Subject: [PATCH 333/345] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230927.3 (#92762) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23471.3 -> To Version 1.0.0-prerelease.23477.3 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a9b02fff630165..9896dec90d5913 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 1d451c32dda2314c721adbf8829e1c0cd4e681ff - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ee166d79f3a269d2a1c6b7d400df7e284b1aa67b + a268dec2bc8ad282a525897b428cf014d5181f77 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ee166d79f3a269d2a1c6b7d400df7e284b1aa67b + a268dec2bc8ad282a525897b428cf014d5181f77 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ee166d79f3a269d2a1c6b7d400df7e284b1aa67b + a268dec2bc8ad282a525897b428cf014d5181f77 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ee166d79f3a269d2a1c6b7d400df7e284b1aa67b + a268dec2bc8ad282a525897b428cf014d5181f77 https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ee166d79f3a269d2a1c6b7d400df7e284b1aa67b + a268dec2bc8ad282a525897b428cf014d5181f77 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - ee166d79f3a269d2a1c6b7d400df7e284b1aa67b + a268dec2bc8ad282a525897b428cf014d5181f77 diff --git a/eng/Versions.props b/eng/Versions.props index ef222884b7cd94..216a4a7406b946 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -158,12 +158,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23471.3 - 1.0.0-prerelease.23471.3 - 1.0.0-prerelease.23471.3 - 1.0.0-prerelease.23471.3 - 1.0.0-prerelease.23471.3 - 1.0.0-prerelease.23471.3 + 1.0.0-prerelease.23477.3 + 1.0.0-prerelease.23477.3 + 1.0.0-prerelease.23477.3 + 1.0.0-prerelease.23477.3 + 1.0.0-prerelease.23477.3 + 1.0.0-prerelease.23477.3 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 From f1e4e90e2c125c6066d96bb0b8d64163b1def1a7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 29 Sep 2023 16:38:07 -0700 Subject: [PATCH 334/345] Update dependencies from https://dev.azure.com/dnceng/internal/_git/dotnet-optimization build 20230928.3 (#92816) optimization.linux-arm64.MIBC.Runtime , optimization.linux-x64.MIBC.Runtime , optimization.windows_nt-arm64.MIBC.Runtime , optimization.windows_nt-x64.MIBC.Runtime , optimization.windows_nt-x86.MIBC.Runtime , optimization.PGO.CoreCLR From Version 1.0.0-prerelease.23477.3 -> To Version 1.0.0-prerelease.23478.3 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 24 ++++++++++++------------ eng/Versions.props | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9896dec90d5913..cfcc40d6319b9d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -334,21 +334,21 @@ https://github.com/dotnet/arcade 1d451c32dda2314c721adbf8829e1c0cd4e681ff - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - a268dec2bc8ad282a525897b428cf014d5181f77 + 492f7464d31d9599531fab2a67bc2422046f5133 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - a268dec2bc8ad282a525897b428cf014d5181f77 + 492f7464d31d9599531fab2a67bc2422046f5133 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - a268dec2bc8ad282a525897b428cf014d5181f77 + 492f7464d31d9599531fab2a67bc2422046f5133 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - a268dec2bc8ad282a525897b428cf014d5181f77 + 492f7464d31d9599531fab2a67bc2422046f5133 https://github.com/dotnet/hotreload-utils @@ -384,13 +384,13 @@ d10b02ae5cc670609d920a672985ed4456bdd6b6 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - a268dec2bc8ad282a525897b428cf014d5181f77 + 492f7464d31d9599531fab2a67bc2422046f5133 - + https://dev.azure.com/dnceng/internal/_git/dotnet-optimization - a268dec2bc8ad282a525897b428cf014d5181f77 + 492f7464d31d9599531fab2a67bc2422046f5133 diff --git a/eng/Versions.props b/eng/Versions.props index 216a4a7406b946..ccc6ce33edf6c6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -158,12 +158,12 @@ 8.0.0-beta.23421.1 8.0.0-beta.23421.1 - 1.0.0-prerelease.23477.3 - 1.0.0-prerelease.23477.3 - 1.0.0-prerelease.23477.3 - 1.0.0-prerelease.23477.3 - 1.0.0-prerelease.23477.3 - 1.0.0-prerelease.23477.3 + 1.0.0-prerelease.23478.3 + 1.0.0-prerelease.23478.3 + 1.0.0-prerelease.23478.3 + 1.0.0-prerelease.23478.3 + 1.0.0-prerelease.23478.3 + 1.0.0-prerelease.23478.3 16.11.29-beta1.23404.4 2.0.0-beta4.23307.1 From 8632a7572473caeab7c4eb29d2a1b82fc31a1fc1 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Tue, 3 Oct 2023 04:34:52 +0200 Subject: [PATCH 335/345] Changes from https://github.com/dotnet/runtime/pull/92630 (#92753) --- .../BrowserDebugProxy/EvaluateExpression.cs | 4 +- .../MemberReferenceResolver.cs | 120 ++++++++++++------ .../EvaluateOnCallFrame2Tests.cs | 18 +++ .../EvaluateOnCallFrameTests.cs | 4 +- .../debugger-test/debugger-evaluate-test.cs | 6 +- 5 files changed, 106 insertions(+), 46 deletions(-) diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs b/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs index c384f74e9c7223..45d700e122ea7f 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs @@ -387,12 +387,14 @@ private static async Task> ResolveElementAccess(ExpressionSyntaxR { var values = new List(); JObject index = null; + List nestedIndexers = new(); IEnumerable elementAccesses = replacer.elementAccess; foreach (ElementAccessExpressionSyntax elementAccess in elementAccesses.Reverse()) { - index = await resolver.Resolve(elementAccess, replacer.memberAccessValues, index, replacer.variableDefinitions, token); + index = await resolver.Resolve(elementAccess, replacer.memberAccessValues, nestedIndexers, replacer.variableDefinitions, token); if (index == null) throw new ReturnAsErrorException($"Failed to resolve element access for {elementAccess}", "ReferenceError"); + nestedIndexers.Add(index); } values.Add(index); return values; diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs index 650583a9dc7bf2..e1b9583ddbe3e1 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs @@ -366,7 +366,12 @@ async Task ResolveAsInstanceMember(ArraySegment parts, JObject } } - public async Task Resolve(ElementAccessExpressionSyntax elementAccess, Dictionary memberAccessValues, JObject indexObject, List variableDefinitions, CancellationToken token) + public async Task Resolve( + ElementAccessExpressionSyntax elementAccess, + Dictionary memberAccessValues, + List nestedIndexObject, + List variableDefinitions, + CancellationToken token) { try { @@ -376,12 +381,13 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, if (rootObject == null) { - // it might be a jagged array where indexObject should be treated as a new rootObject - rootObject = indexObject; - indexObject = null; + // it might be a jagged array where the previously added nestedIndexObject should be treated as a new rootObject + rootObject = nestedIndexObject.LastOrDefault(); + if (rootObject != null) + nestedIndexObject.RemoveAt(nestedIndexObject.Count - 1); } - ElementIndexInfo elementIdxInfo = await GetElementIndexInfo(); + ElementIndexInfo elementIdxInfo = await GetElementIndexInfo(nestedIndexObject); if (elementIdxInfo is null) return null; @@ -394,6 +400,7 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, if (!DotnetObjectId.TryParse(rootObject?["objectId"]?.Value(), out DotnetObjectId objectId)) throw new InvalidOperationException($"Cannot apply indexing with [] to a primitive object of type '{type}'"); + bool isMultidimensional = elementIdxInfo.DimensionsCount != 1; switch (objectId.Scheme) { case "valuetype": //can be an inlined array @@ -407,7 +414,7 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, } case "array": rootObject["value"] = await context.SdbAgent.GetArrayValues(objectId.Value, token); - if (!elementIdxInfo.IsMultidimensional) + if (!isMultidimensional) { int.TryParse(elementIdxInfo.ElementIdxStr, out elementIdx); return (JObject)rootObject["value"][elementIdx]["value"]; @@ -417,10 +424,8 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, return (JObject)(((JArray)rootObject["value"]).FirstOrDefault(x => x["name"].Value() == elementIdxInfo.ElementIdxStr)["value"]); } case "object": - if (elementIdxInfo.IsMultidimensional) - throw new InvalidOperationException($"Cannot apply indexing with [,] to an object of type '{type}'"); // ToDo: try to use the get_Item for string as well - if (type == "string") + if (!isMultidimensional && type == "string") { var eaExpressionFormatted = elementAccessStrExpression.Replace('.', '_'); // instance_str variableDefinitions.Add(new (eaExpressionFormatted, rootObject, ExpressionEvaluator.ConvertJSToCSharpLocalVariableAssignment(eaExpressionFormatted, rootObject))); @@ -428,7 +433,7 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, var variableDef = await ExpressionEvaluator.GetVariableDefinitions(this, variableDefinitions, invokeToStringInObject: false, token); return await ExpressionEvaluator.EvaluateSimpleExpression(this, eaFormatted, elementAccessStr, variableDef, logger, token); } - if (indexObject is null && elementIdxInfo.IndexingExpression is null) + if (elementIdxInfo.Indexers is null || elementIdxInfo.Indexers.Count == 0) throw new InternalErrorException($"Unable to write index parameter to invoke the method in the runtime."); var typeIds = await context.SdbAgent.GetTypeIdsForObject(objectId.Value, true, token); @@ -441,15 +446,13 @@ public async Task Resolve(ElementAccessExpressionSyntax elementAccess, { MethodInfoWithDebugInformation methodInfo = await context.SdbAgent.GetMethodInfo(methodIds[i], token); ParameterInfo[] paramInfo = methodInfo.GetParametersInfo(); - if (paramInfo.Length == 1) + if (paramInfo.Length == elementIdxInfo.DimensionsCount) { try { - if (indexObject != null && !CheckParametersCompatibility(paramInfo[0].TypeCode, indexObject)) + if (!CheckParametersCompatibility(paramInfo, elementIdxInfo.Indexers)) continue; - ArraySegment buffer = indexObject is null ? - await WriteLiteralExpressionAsIndex(objectId, elementIdxInfo.IndexingExpression, elementIdxInfo.ElementIdxStr) : - await WriteJObjectAsIndex(objectId, indexObject, elementIdxInfo.ElementIdxStr, paramInfo[0].TypeCode); + ArraySegment buffer = await WriteIndexObjectAsIndices(objectId, elementIdxInfo.Indexers, paramInfo); JObject getItemRetObj = await context.SdbAgent.InvokeMethod(buffer, methodIds[i], token); return (JObject)getItemRetObj["value"]; } @@ -470,31 +473,32 @@ await WriteLiteralExpressionAsIndex(objectId, elementIdxInfo.IndexingExpression, throw new ReturnAsErrorException($"Unable to evaluate element access '{elementAccess}': {ex.Message}", ex.GetType().Name); } - async Task GetElementIndexInfo() + async Task GetElementIndexInfo(List nestedIndexers) { - // e.g. x[a[0]], x[a[b[1]]] etc. - if (indexObject is not null) - return new ElementIndexInfo(ElementIdxStr: indexObject["value"].ToString() ); - if (elementAccess.ArgumentList is null) return null; - StringBuilder elementIdxStr = new StringBuilder(); - var multiDimensionalArray = false; + int dimCnt = elementAccess.ArgumentList.Arguments.Count; LiteralExpressionSyntax indexingExpression = null; - for (int i = 0; i < elementAccess.ArgumentList.Arguments.Count; i++) + StringBuilder elementIdxStr = new StringBuilder(); + List indexers = new(); + // nesting should be resolved in reverse order + int nestedIndexersCnt = nestedIndexers.Count - 1; + for (int i = 0; i < dimCnt; i++) { + JObject indexObject; var arg = elementAccess.ArgumentList.Arguments[i]; if (i != 0) { elementIdxStr.Append(", "); - multiDimensionalArray = true; } // e.g. x[1] if (arg.Expression is LiteralExpressionSyntax) { indexingExpression = arg.Expression as LiteralExpressionSyntax; - elementIdxStr.Append(indexingExpression.ToString()); + string expression = indexingExpression.ToString(); + elementIdxStr.Append(expression); + indexers.Add(indexingExpression); } // e.g. x[a] or x[a.b] @@ -508,6 +512,18 @@ async Task GetElementIndexInfo() // x[a] indexObject ??= await Resolve(argParm.Identifier.Text, token); elementIdxStr.Append(indexObject["value"].ToString()); + indexers.Add(indexObject); + } + // nested indexing, e.g. x[a[0]], x[a[b[1]]], x[a[0], b[1]] + else if (arg.Expression is ElementAccessExpressionSyntax) + { + if (nestedIndexers == null || nestedIndexersCnt < 0) + throw new InvalidOperationException($"Cannot resolve nested indexing"); + JObject nestedIndexObject = nestedIndexers[nestedIndexersCnt]; + nestedIndexers.RemoveAt(nestedIndexersCnt); + elementIdxStr.Append(nestedIndexObject["value"].ToString()); + indexers.Add(nestedIndexObject); + nestedIndexersCnt--; } // indexing with expressions, e.g. x[a + 1] else @@ -519,36 +535,57 @@ async Task GetElementIndexInfo() if (idxType != "number") throw new InvalidOperationException($"Cannot index with an object of type '{idxType}'"); elementIdxStr.Append(indexObject["value"].ToString()); + indexers.Add(indexObject); } } return new ElementIndexInfo( + DimensionsCount: dimCnt, ElementIdxStr: elementIdxStr.ToString(), - IsMultidimensional: multiDimensionalArray, - IndexingExpression: indexingExpression); + Indexers: indexers); } - async Task> WriteJObjectAsIndex(DotnetObjectId rootObjId, JObject indexObject, string elementIdxStr, ElementType? expectedType) + async Task> WriteIndexObjectAsIndices(DotnetObjectId rootObjId, List indexObjects, ParameterInfo[] paramInfo) { using var writer = new MonoBinaryWriter(); writer.WriteObj(rootObjId, context.SdbAgent); - writer.Write(1); // number of method args - if (!await writer.WriteJsonValue(indexObject, context.SdbAgent, expectedType, token)) - throw new InternalErrorException($"Parsing index of type {indexObject["type"].Value()} to write it into the buffer failed."); + writer.Write(indexObjects.Count); // number of method args + foreach ((ParameterInfo pi, object indexObject) in paramInfo.Zip(indexObjects)) + { + if (indexObject is JObject indexJObject) + { + // indexed by an identifier name syntax + if (!await writer.WriteJsonValue(indexJObject, context.SdbAgent, pi.TypeCode, token)) + throw new InternalErrorException($"Parsing index of type {indexJObject["type"].Value()} to write it into the buffer failed."); + } + else if (indexObject is LiteralExpressionSyntax expression) + { + // indexed by a literal expression syntax + if (!await writer.WriteConst(expression, context.SdbAgent, token)) + throw new InternalErrorException($"Parsing literal expression index = {expression} to write it into the buffer failed."); + } + else + { + throw new InternalErrorException($"Unexpected index type."); + } + } return writer.GetParameterBuffer(); } + } - async Task> WriteLiteralExpressionAsIndex(DotnetObjectId rootObjId, LiteralExpressionSyntax indexingExpression, string elementIdxStr) + private static bool CheckParametersCompatibility(ParameterInfo[] paramInfos, List indexObjects) + { + if (paramInfos.Length != indexObjects.Count) + return false; + foreach ((ParameterInfo paramInfo, object indexObj) in paramInfos.Zip(indexObjects)) { - using var writer = new MonoBinaryWriter(); - writer.WriteObj(rootObjId, context.SdbAgent); - writer.Write(1); // number of method args - if (!await writer.WriteConst(indexingExpression, context.SdbAgent, token)) - throw new InternalErrorException($"Parsing index of type {indexObject["type"].Value()} to write it into the buffer failed."); - return writer.GetParameterBuffer(); + // shouldn't we check LiteralExpressionSyntax for compatibility as well? + if (indexObj is JObject indexJObj && !CheckParameterCompatibility(paramInfo.TypeCode, indexJObj)) + return false; } + return true; } - private static bool CheckParametersCompatibility(ElementType? paramTypeCode, JObject value) + private static bool CheckParameterCompatibility(ElementType? paramTypeCode, JObject value) { if (!paramTypeCode.HasValue) return true; @@ -871,7 +908,8 @@ public JObject TryGetEvaluationResult(string id) private sealed record ElementIndexInfo( string ElementIdxStr, - bool IsMultidimensional = false, - LiteralExpressionSyntax IndexingExpression = null); + // keeps JObjects and LiteralExpressionSyntaxes: + List Indexers, + int DimensionsCount = 1); } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs index 051da33469ce2d..b1a79b28ceeefe 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrame2Tests.cs @@ -731,5 +731,23 @@ await CheckEvaluateFail(id, ("dt+1", "Cannot evaluate '(dt+1\n)': (2,9): error CS0019: Operator '+' cannot be applied to operands of type 'object' and 'int'") ); }); + + [Fact] + public async Task EvaluateObjectIndexingMultidimensional() => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.EvaluateLocalsWithIndexingTests", "EvaluateLocals", 12, "DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", + "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateLocalsWithIndexingTests:EvaluateLocals'); })", + wait_for_event_fn: async (pause_location) => + { + var id = pause_location["callFrames"][0]["callFrameId"].Value(); + await EvaluateOnCallFrameAndCheck(id, + ("f[j, aDouble]", TNumber("3.34")), //only IdentifierNameSyntaxes + ("f[1, aDouble]", TNumber("3.34")), //IdentifierNameSyntax with LiteralExpressionSyntax + ("f[aChar, \"&\", longString]", TString("9-&-longString")), + ("f[f.numArray[j], aDouble]", TNumber("4.34")), //ElementAccessExpressionSyntax + ("f[f.numArray[j], f.numArray[0]]", TNumber("3")), //multiple ElementAccessExpressionSyntaxes + ("f[f.numArray[f.numList[0]], f.numArray[i]]", TNumber("3")), + ("f[f.numArray[f.numList[0]], f.numArray[f.numArray[i]]]", TNumber("4")) + ); + }); } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index 2ff9bd26a28272..2d0fb87822758a 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -585,7 +585,7 @@ public async Task EvaluateIndexingNegative() => await CheckInspectLocalsAtBreakp Assert.Equal("Unable to evaluate element access 'f.idx0[2]': Cannot apply indexing with [] to a primitive object of type 'number'", res.Error["result"]?["description"]?.Value()); var exceptionDetailsStack = res.Error["exceptionDetails"]?["stackTrace"]?["callFrames"]?[0]; Assert.Equal("DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", exceptionDetailsStack?["functionName"]?.Value()); - Assert.Equal(556, exceptionDetailsStack?["lineNumber"]?.Value()); + Assert.Equal(558, exceptionDetailsStack?["lineNumber"]?.Value()); Assert.Equal(12, exceptionDetailsStack?["columnNumber"]?.Value()); (_, res) = await EvaluateOnCallFrame(id, "f[1]", expect_ok: false ); Assert.Equal( "Unable to evaluate element access 'f[1]': Cannot apply indexing with [] to an object of type 'DebuggerTests.EvaluateLocalsWithIndexingTests.TestEvaluate'", res.Error["result"]?["description"]?.Value()); @@ -722,7 +722,7 @@ public async Task EvaluateIndexingByExpressionNegative() => await CheckInspectLo Assert.Equal("Unable to evaluate element access 'f.numList[\"a\" + 1]': Cannot index with an object of type 'string'", res.Error["result"]?["description"]?.Value()); var exceptionDetailsStack = res.Error["exceptionDetails"]?["stackTrace"]?["callFrames"]?[0]; Assert.Equal("DebuggerTests.EvaluateLocalsWithIndexingTests.EvaluateLocals", exceptionDetailsStack?["functionName"]?.Value()); - Assert.Equal(556, exceptionDetailsStack?["lineNumber"]?.Value()); + Assert.Equal(558, exceptionDetailsStack?["lineNumber"]?.Value()); Assert.Equal(12, exceptionDetailsStack?["columnNumber"]?.Value()); }); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs index 480dc30115c430..e46177ecc925b5 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs @@ -522,7 +522,6 @@ public class TestEvaluate public int idx0; public int idx1; - // ToDo: add 2d indexing - https://github.com/dotnet/runtime/issues/76062 public string this[char key] => "res_" + key; public string this[bool key] => key.ToString(); public bool this[string key] => key.Length > 3; @@ -530,11 +529,14 @@ public class TestEvaluate public int this[float key] => (int)key; public int this[decimal key] => (int)key; + public double this[int key1, double key2] => key1 + key2; + public string this[char key1, string key2, string key3] => $"{key1}-{key2}-{key3}"; + public void run() { numList = new List { 1, 2 }; textList = new List { "1", "2" }; - numArray = new int[] { 1, 2 }; + numArray = new int[] { 1, 2, 0 }; textArray = new string[] { "1", "2" }; numArrayOfArrays = new int[][] { numArray, numArray }; numListOfLists = new List> { numList, numList }; From 172d79a458e9468e74bba60dc061a5c94aa21eca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 19:35:29 -0700 Subject: [PATCH 336/345] [release/8.0] [browser] Remove duplicated marshaling of return value for JSExport (#92886) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove duplicated marshaling of return value for JSExport * Move unmarshal and return value marshal into try block --------- Co-authored-by: Marek Fišera --- .../JSExportCodeGenerator.cs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs index 0a18241ef7c767..a00fc9e4024f76 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportCodeGenerator.cs @@ -59,7 +59,7 @@ public JSExportCodeGenerator( public BlockSyntax GenerateJSExportBody() { - StatementSyntax invoke = InvokeSyntax(); + List invoke = InvokeSyntax(); GeneratedStatements statements = GeneratedStatements.Create(_marshallers, _context); bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.CleanupCallerAllocated.IsEmpty || !statements.CleanupCalleeAllocated.IsEmpty; VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForUnmanagedToManaged(_marshallers, _context, shouldInitializeVariables); @@ -79,7 +79,7 @@ public BlockSyntax GenerateJSExportBody() var tryStatements = new List(); tryStatements.AddRange(statements.Unmarshal); - tryStatements.Add(invoke); + tryStatements.AddRange(invoke); if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty)) { @@ -93,6 +93,18 @@ public BlockSyntax GenerateJSExportBody() tryStatements.AddRange(statements.Marshal); List allStatements = setupStatements; + + // Wrap unmarshall, invocation and return value marshalling in try-catch. + // In case of exception, marshal exception instead of return value. + var tryInvokeAndMarshal = TryStatement(SingletonList(CatchClause() + .WithDeclaration(CatchDeclaration(IdentifierName(Constants.ExceptionGlobal)).WithIdentifier(Identifier("ex"))) + .WithBlock(Block(SingletonList( + ExpressionStatement(InvocationExpression( + MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(Constants.ArgumentException), IdentifierName(Constants.ToJSMethod))) + .WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(IdentifierName("ex"))))))))))) + .WithBlock(Block(tryStatements)); + List finallyStatements = new List(); if (!(statements.GuaranteedUnmarshal.IsEmpty && statements.CleanupCalleeAllocated.IsEmpty)) { @@ -100,16 +112,14 @@ public BlockSyntax GenerateJSExportBody() } finallyStatements.AddRange(statements.CleanupCallerAllocated); + if (finallyStatements.Count > 0) { - allStatements.Add( - TryStatement(Block(tryStatements), default, FinallyClause(Block(finallyStatements)))); - } - else - { - allStatements.AddRange(tryStatements); + tryInvokeAndMarshal = TryStatement(Block(tryInvokeAndMarshal), default, FinallyClause(Block(finallyStatements))); } + allStatements.Add(tryInvokeAndMarshal); + return Block(allStatements); } @@ -175,7 +185,7 @@ private void SetupSyntax(List statementsToUpdate) Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(1))))))))))))); } - private TryStatementSyntax InvokeSyntax() + private List InvokeSyntax() { var statements = new List(); var arguments = new List(); @@ -205,16 +215,8 @@ private TryStatementSyntax InvokeSyntax() IdentifierName(nativeIdentifier), invocation)); statements.Add(statement); - statements.AddRange(_marshallers.ManagedReturnMarshaller.Generator.Generate(_marshallers.ManagedReturnMarshaller.TypeInfo, _context with { CurrentStage = StubCodeContext.Stage.Marshal })); } - return TryStatement(SingletonList(CatchClause() - .WithDeclaration(CatchDeclaration(IdentifierName(Constants.ExceptionGlobal)).WithIdentifier(Identifier("ex"))) - .WithBlock(Block(SingletonList( - ExpressionStatement(InvocationExpression( - MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(Constants.ArgumentException), IdentifierName(Constants.ToJSMethod))) - .WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(IdentifierName("ex"))))))))))) - .WithBlock(Block(statements)); + return statements; } From 8e365ee9e1c1b4da3300b0ecb672ea7c85b1f220 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 19:35:48 -0700 Subject: [PATCH 337/345] fix https://github.com/dotnet/runtime/issues/92713 (#92890) Co-authored-by: pavelsavara --- src/mono/wasm/runtime/startup.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index d8eab74d8b2500..c385844dfd30bb 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -5,7 +5,7 @@ import MonoWasmThreads from "consts:monoWasmThreads"; import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop"; import { DotnetModuleInternal, CharPtrNull } from "./types/internal"; -import { linkerDisableLegacyJsInterop, ENVIRONMENT_IS_PTHREAD, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, linkerWasmEnableSIMD, linkerWasmEnableEH } from "./globals"; +import { linkerDisableLegacyJsInterop, ENVIRONMENT_IS_PTHREAD, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, linkerWasmEnableSIMD, linkerWasmEnableEH, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WORKER } from "./globals"; import cwraps, { init_c_exports } from "./cwraps"; import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug"; import { toBase64StringImpl } from "./base64"; @@ -273,6 +273,10 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { bindings_init(); runtimeHelpers.runtimeReady = true; + if (ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER) { + Module.runtimeKeepalivePush(); + } + if (MonoWasmThreads) { runtimeHelpers.javaScriptExports.install_synchronization_context(); runtimeHelpers.jsSynchronizationContextInstalled = true; From ef6283ac0a14c78d9e9fef4841545099bd7ad12b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 19:39:16 -0700 Subject: [PATCH 338/345] [release/8.0] Update dependencies from dotnet/roslyn (#92503) * Update dependencies from https://github.com/dotnet/roslyn build 20230922.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.9 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.9 * Update dependencies from https://github.com/dotnet/roslyn build 20230922.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23472.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230923.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23473.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230923.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23473.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230923.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23473.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230923.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23473.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230924.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23474.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230924.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23474.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230924.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23474.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.2 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.2 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.5 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.5 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.6 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.7 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.7 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.8 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.8 * Update dependencies from https://github.com/dotnet/roslyn build 20230925.10 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23475.10 * Update dependencies from https://github.com/dotnet/roslyn build 20230926.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230926.6 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.6 * Small refactor to BuildElement to address NRT changes * Update dependencies from https://github.com/dotnet/roslyn build 20230926.13 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.13 * Update dependencies from https://github.com/dotnet/roslyn build 20230926.14 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.14 * Update dependencies from https://github.com/dotnet/roslyn build 20230926.15 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.15 * Update dependencies from https://github.com/dotnet/roslyn build 20230926.21 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.21 * Update dependencies from https://github.com/dotnet/roslyn build 20230926.22 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23476.22 * Update dependencies from https://github.com/dotnet/roslyn build 20230927.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23477.1 * Update dependencies from https://github.com/dotnet/roslyn build 20230927.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23477.4 * Update dependencies from https://github.com/dotnet/roslyn build 20230928.3 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23478.3 * Update dependencies from https://github.com/dotnet/roslyn build 20230928.4 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23478.4 * Update dependencies from https://github.com/dotnet/roslyn build 20231001.1 Microsoft.CodeAnalysis , Microsoft.CodeAnalysis.CSharp , Microsoft.Net.Compilers.Toolset From Version 4.8.0-3.23472.2 -> To Version 4.8.0-3.23501.1 --------- Co-authored-by: dotnet-maestro[bot] Co-authored-by: Levi Broderick Co-authored-by: Fred Silberberg --- eng/Version.Details.xml | 12 ++++++------ eng/Versions.props | 6 +++--- .../X509Certificates/ChainPal.Apple.cs | 16 +++++++--------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cfcc40d6319b9d..1f220ede26d087 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -358,18 +358,18 @@ https://github.com/dotnet/runtime-assets 99168dcff56809205e7ef8530d1256f3a07fab1f - + https://github.com/dotnet/roslyn - aa7e4da5341196be494ca4bb0c719d7bef3e396a + 0d735148bbb4cb511be547fbc1db63a2c81a821d - + https://github.com/dotnet/roslyn - aa7e4da5341196be494ca4bb0c719d7bef3e396a + 0d735148bbb4cb511be547fbc1db63a2c81a821d - + https://github.com/dotnet/roslyn - aa7e4da5341196be494ca4bb0c719d7bef3e396a + 0d735148bbb4cb511be547fbc1db63a2c81a821d https://github.com/dotnet/roslyn-analyzers diff --git a/eng/Versions.props b/eng/Versions.props index ccc6ce33edf6c6..1663485ec06805 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -44,9 +44,9 @@ 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. --> - 4.8.0-3.23472.2 - 4.8.0-3.23472.2 - 4.8.0-3.23472.2 + 4.8.0-3.23501.1 + 4.8.0-3.23501.1 + 4.8.0-3.23501.1 @@ -17,15 +22,19 @@ - - - + + + + + + + @@ -38,20 +47,20 @@ - + + - - + + + - - diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/BinderInvocation.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/BinderInvocation.cs index ad7c4c09204d4b..b1cf51acb3b4a6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/BinderInvocation.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/BinderInvocation.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; @@ -9,8 +9,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record BinderInvocation(IInvocationOperation Operation, Location Location) + internal sealed class BinderInvocation { + private BinderInvocation(IInvocationOperation operation, Location location) + { + Operation = operation; + Location = location; + } + + public IInvocationOperation Operation { get; } + public Location Location { get; } + public static BinderInvocation? Create(GeneratorSyntaxContext context, CancellationToken cancellationToken) { Debug.Assert(IsCandidateSyntaxNode(context.Node)); @@ -35,8 +44,8 @@ public static bool IsCandidateSyntaxNode(SyntaxNode node) } && IsCandidateBindingMethodName(memberName); static bool IsCandidateBindingMethodName(string name) => - IsCandidateMethodName_ConfigurationBinder(name) || - IsCandidateMethodName_OptionsBuilderConfigurationExtensions(name) || + IsValidMethodName_ConfigurationBinder(name) || + IsValidMethodName_OptionsBuilderConfigurationExtensions(name) || IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name); } @@ -62,10 +71,10 @@ public static bool IsBindingOperation(IInvocationOperation operation) { "ConfigurationBinder" => containingNamespaceName is "Microsoft.Extensions.Configuration" && - IsCandidateMethodName_ConfigurationBinder(methodName), + IsValidMethodName_ConfigurationBinder(methodName), "OptionsBuilderConfigurationExtensions" => containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && - IsCandidateMethodName_OptionsBuilderConfigurationExtensions(methodName), + IsValidMethodName_OptionsBuilderConfigurationExtensions(methodName), "OptionsConfigurationServiceCollectionExtensions" => containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(methodName), @@ -73,16 +82,10 @@ containingNamespaceName is "Microsoft.Extensions.DependencyInjection" && }; } - private static bool IsCandidateMethodName_ConfigurationBinder(string name) => name is - nameof(MethodsToGen_ConfigurationBinder.Bind) or - nameof(MethodsToGen_ConfigurationBinder.Get) or - nameof(MethodsToGen_ConfigurationBinder.GetValue); + private static bool IsValidMethodName_ConfigurationBinder(string name) => name is "Bind" or "Get" or "GetValue"; - private static bool IsCandidateMethodName_OptionsBuilderConfigurationExtensions(string name) => name is - nameof(MethodsToGen_Extensions_OptionsBuilder.Bind) or - nameof(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration); + private static bool IsValidMethodName_OptionsBuilderConfigurationExtensions(string name) => name is "Bind" or "BindConfiguration"; - private static bool IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(string name) => name is - nameof(MethodsToGen_Extensions_ServiceCollection.Configure); + private static bool IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(string name) => name is "Configure"; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs index 3996142adf9089..645786e35c1c55 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/ConfigurationBinder.cs @@ -6,28 +6,29 @@ using System.Linq; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis; +using System.Diagnostics; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { public sealed partial class ConfigurationBindingGenerator { - private sealed partial class Parser + internal sealed partial class Parser { private void ParseInvocation_ConfigurationBinder(BinderInvocation invocation) { switch (invocation.Operation.TargetMethod.Name) { - case nameof(MethodsToGen_ConfigurationBinder.Bind): + case "Bind": { ParseBindInvocation_ConfigurationBinder(invocation); } break; - case nameof(MethodsToGen_ConfigurationBinder.Get): + case "Get": { ParseGetInvocation(invocation); } break; - case nameof(MethodsToGen_ConfigurationBinder.GetValue): + case "GetValue": { ParseGetValueInvocation(invocation); } @@ -46,39 +47,39 @@ private void ParseBindInvocation_ConfigurationBinder(BinderInvocation invocation return; } - MethodsToGen_ConfigurationBinder overload = MethodsToGen_ConfigurationBinder.None; + MethodsToGen overload = MethodsToGen.None; if (paramCount is 2) { - overload = MethodsToGen_ConfigurationBinder.Bind_instance; + overload = MethodsToGen.ConfigBinder_Bind_instance; } else if (paramCount is 3) { if (@params[1].Type.SpecialType is SpecialType.System_String) { - overload = MethodsToGen_ConfigurationBinder.Bind_key_instance; + overload = MethodsToGen.ConfigBinder_Bind_key_instance; } else if (SymbolEqualityComparer.Default.Equals(@params[2].Type, _typeSymbols.ActionOfBinderOptions)) { - overload = MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions; + overload = MethodsToGen.ConfigBinder_Bind_instance_BinderOptions; } } - if (overload is MethodsToGen_ConfigurationBinder.None) + if (overload is MethodsToGen.None) { return; } int instanceIndex = overload switch { - MethodsToGen_ConfigurationBinder.Bind_instance => 1, - MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => 1, - MethodsToGen_ConfigurationBinder.Bind_key_instance => 2, + MethodsToGen.ConfigBinder_Bind_instance => 1, + MethodsToGen.ConfigBinder_Bind_instance_BinderOptions => 1, + MethodsToGen.ConfigBinder_Bind_key_instance => 2, _ => throw new InvalidOperationException() }; IArgumentOperation instanceArg = GetArgumentForParameterAtIndex(operation.Arguments, instanceIndex); - if (instanceArg.Parameter.Type.SpecialType != SpecialType.System_Object) + if (instanceArg.Parameter?.Type.SpecialType is not SpecialType.System_Object) { return; } @@ -87,20 +88,17 @@ private void ParseBindInvocation_ConfigurationBinder(BinderInvocation invocation if (!IsValidRootConfigType(type)) { - _context.ReportDiagnostic(Diagnostic.Create(Diagnostics.CouldNotDetermineTypeInfo, invocation.Location)); + RecordDiagnostic(DiagnosticDescriptors.CouldNotDetermineTypeInfo, invocation.Location); return; } - if (type!.IsValueType) + if (type.IsValueType) { - _context.ReportDiagnostic(Diagnostic.Create(Diagnostics.ValueTypesInvalidForBind, invocation.Location, type)); + RecordDiagnostic(DiagnosticDescriptors.ValueTypesInvalidForBind, invocation.Location, messageArgs: new object[] { type }); return; } - if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) - { - RegisterInterceptor(overload, typeSpec, invocation.Operation); - } + EnqueueTargetTypeForRootInvocation(type, overload, invocation); static ITypeSymbol? ResolveType(IOperation conversionOperation) => conversionOperation switch @@ -144,7 +142,7 @@ private void ParseGetInvocation(BinderInvocation invocation) return; } - MethodsToGen_ConfigurationBinder overload = MethodsToGen_ConfigurationBinder.None; + MethodsToGen overload = MethodsToGen.None; ITypeSymbol? type; if (targetMethod.IsGenericMethod) @@ -158,11 +156,11 @@ private void ParseGetInvocation(BinderInvocation invocation) if (paramCount is 1) { - overload = MethodsToGen_ConfigurationBinder.Get_T; + overload = MethodsToGen.ConfigBinder_Get_T; } else if (paramCount is 2 && SymbolEqualityComparer.Default.Equals(@params[1].Type, _typeSymbols.ActionOfBinderOptions)) { - overload = MethodsToGen_ConfigurationBinder.Get_T_BinderOptions; + overload = MethodsToGen.ConfigBinder_Get_T_BinderOptions; } } else if (paramCount > 3) @@ -176,20 +174,15 @@ private void ParseGetInvocation(BinderInvocation invocation) if (paramCount is 2) { - overload = MethodsToGen_ConfigurationBinder.Get_TypeOf; + overload = MethodsToGen.ConfigBinder_Get_TypeOf; } else if (paramCount is 3 && SymbolEqualityComparer.Default.Equals(@params[2].Type, _typeSymbols.ActionOfBinderOptions)) { - overload = MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions; + overload = MethodsToGen.ConfigBinder_Get_TypeOf_BinderOptions; } } - if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec) - { - RegisterInvocation(overload, invocation.Operation); - RegisterTypeForGetCoreGen(typeSpec); - } - + EnqueueTargetTypeForRootInvocation(type, overload, invocation); } private void ParseGetValueInvocation(BinderInvocation invocation) @@ -199,7 +192,7 @@ private void ParseGetValueInvocation(BinderInvocation invocation) ImmutableArray @params = targetMethod.Parameters; int paramCount = @params.Length; - MethodsToGen_ConfigurationBinder overload = MethodsToGen_ConfigurationBinder.None; + MethodsToGen overload = MethodsToGen.None; ITypeSymbol? type; if (targetMethod.IsGenericMethod) @@ -213,11 +206,11 @@ private void ParseGetValueInvocation(BinderInvocation invocation) if (paramCount is 2) { - overload = MethodsToGen_ConfigurationBinder.GetValue_T_key; + overload = MethodsToGen.ConfigBinder_GetValue_T_key; } else if (paramCount is 3 && SymbolEqualityComparer.Default.Equals(@params[2].Type, type)) { - overload = MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue; + overload = MethodsToGen.ConfigBinder_GetValue_T_key_defaultValue; } } else if (paramCount > 4) @@ -236,45 +229,56 @@ private void ParseGetValueInvocation(BinderInvocation invocation) if (paramCount is 3) { - overload = MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key; + overload = MethodsToGen.ConfigBinder_GetValue_TypeOf_key; } else if (paramCount is 4 && @params[3].Type.SpecialType is SpecialType.System_Object) { - overload = MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue; + overload = MethodsToGen.ConfigBinder_GetValue_TypeOf_key_defaultValue; } } - ITypeSymbol effectiveType = (IsNullable(type, out ITypeSymbol? underlyingType) ? underlyingType : type)!; - if (!IsValidRootConfigType(type)) { - _context.ReportDiagnostic(Diagnostic.Create(Diagnostics.CouldNotDetermineTypeInfo, invocation.Location)); + RecordDiagnostic(DiagnosticDescriptors.CouldNotDetermineTypeInfo, invocation.Location); return; } - if (IsParsableFromString(effectiveType, out _) && - GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec) + ITypeSymbol effectiveType = IsNullable(type, out ITypeSymbol? underlyingType) ? underlyingType : type; + + if (IsParsableFromString(effectiveType, out _)) { - RegisterInvocation(overload, invocation.Operation); - RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec); + EnqueueTargetTypeForRootInvocation(type, overload, invocation); } } - private void RegisterInvocation(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation) + private void RegisterInterceptor_ConfigurationBinder(TypeParseInfo typeParseInfo, TypeSpec typeSpec) { - _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; - RegisterInterceptor(overload, operation); - } + MethodsToGen overload = typeParseInfo.BindingOverload; + IInvocationOperation invocationOperation = typeParseInfo.BinderInvocation!.Operation; + Debug.Assert((MethodsToGen.ConfigBinder_Any & overload) is not 0); - /// - /// Registers generated Bind methods as interceptors. This is done differently from other root - /// methods because we need to - /// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects. - /// - private void RegisterInterceptor(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation) - { - _sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload; - _sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation); + if ((MethodsToGen.ConfigBinder_Bind & overload) is not 0) + { + if (typeSpec is ComplexTypeSpec complexTypeSpec && + _helperInfoBuilder!.TryRegisterTransitiveTypesForMethodGen(complexTypeSpec.TypeRef)) + { + _interceptorInfoBuilder.RegisterInterceptor_ConfigBinder_Bind(overload, complexTypeSpec, invocationOperation); + } + } + else + { + Debug.Assert((MethodsToGen.ConfigBinder_Get & overload) is not 0 || + (MethodsToGen.ConfigBinder_GetValue & overload) is not 0); + + bool registered = (MethodsToGen.ConfigBinder_Get & overload) is not 0 + ? _helperInfoBuilder!.TryRegisterTypeForGetGen(typeSpec) + : _helperInfoBuilder!.TryRegisterTypeForGetValueGen(typeSpec); + + if (registered) + { + _interceptorInfoBuilder.RegisterInterceptor(overload, invocationOperation); + } + } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Diagnostics.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/DiagnosticDescriptors.cs similarity index 82% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Diagnostics.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/DiagnosticDescriptors.cs index d6d816545bcd0a..3f694c78be8309 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Diagnostics.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/DiagnosticDescriptors.cs @@ -9,9 +9,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { public sealed partial class ConfigurationBindingGenerator { - private sealed partial class Parser + internal sealed partial class Parser { - internal static class Diagnostics + private static class DiagnosticDescriptors { public static DiagnosticDescriptor TypeNotSupported { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.TypeNotSupported)); public static DiagnosticDescriptor MissingPublicInstanceConstructor { get; } = CreateTypeNotSupportedDescriptor(nameof(SR.MissingPublicInstanceConstructor)); @@ -62,6 +62,20 @@ private static DiagnosticDescriptor CreateTypeNotSupportedDescriptor(string name category: ProjectName, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public static DiagnosticDescriptor GetNotSupportedDescriptor(NotSupportedReason reason) => + reason switch + { + NotSupportedReason.UnknownType => TypeNotSupported, + NotSupportedReason.MissingPublicInstanceConstructor => MissingPublicInstanceConstructor, + NotSupportedReason.CollectionNotSupported => CollectionNotSupported, + NotSupportedReason.DictionaryKeyNotSupported => DictionaryKeyNotSupported, + NotSupportedReason.ElementTypeNotSupported => ElementTypeNotSupported, + NotSupportedReason.MultipleParameterizedConstructors => MultipleParameterizedConstructors, + NotSupportedReason.MultiDimArraysNotSupported => MultiDimArraysNotSupported, + NotSupportedReason.NullableUnderlyingTypeNotSupported => NullableUnderlyingTypeNotSupported, + _ => throw new InvalidOperationException() + }; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs index fa0b3691ec4047..f685842639966a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/Extensions.cs @@ -8,6 +8,54 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { + public sealed partial class ConfigurationBindingGenerator + { + internal sealed partial class Parser + { + private readonly struct TypeParseInfo + { + public ITypeSymbol TypeSymbol { get; private init; } + public string TypeName { get; private init; } + public MethodsToGen BindingOverload { get; private init; } + public BinderInvocation BinderInvocation { get; private init; } + public ContainingTypeDiagnosticInfo? ContainingTypeDiagnosticInfo { get; private init; } + + public static TypeParseInfo Create(ITypeSymbol typeSymbol, MethodsToGen overload, BinderInvocation invocation, ContainingTypeDiagnosticInfo? containingTypeDiagInfo = null) => + new TypeParseInfo + { + TypeSymbol = typeSymbol, + TypeName = typeSymbol.GetName(), + BindingOverload = overload, + BinderInvocation = invocation, + ContainingTypeDiagnosticInfo = containingTypeDiagInfo, + }; + + public TypeParseInfo ToTransitiveTypeParseInfo(ITypeSymbol memberType, DiagnosticDescriptor? diagDescriptor = null, string? memberName = null) + { + ContainingTypeDiagnosticInfo? diagnosticInfo = diagDescriptor is null + ? null + : new() + { + TypeName = TypeName, + Descriptor = diagDescriptor, + MemberName = memberName, + ContainingTypeInfo = ContainingTypeDiagnosticInfo, + }; + + return Create(memberType, BindingOverload, BinderInvocation, diagnosticInfo); + } + } + + private sealed class ContainingTypeDiagnosticInfo + { + public required string TypeName { get; init; } + public required string? MemberName { get; init; } + public required DiagnosticDescriptor Descriptor { get; init; } + public required ContainingTypeDiagnosticInfo? ContainingTypeInfo { get; init; } + } + } + } + internal static class ParserExtensions { private static readonly SymbolDisplayFormat s_identifierCompatibleFormat = new SymbolDisplayFormat( @@ -16,6 +64,12 @@ internal static class ParserExtensions genericsOptions: SymbolDisplayGenericsOptions.None, miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + private static readonly SymbolDisplayFormat s_minimalDisplayFormat = new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes); + public static void RegisterCacheEntry(this Dictionary cache, TKey key, TEntry entry) where TKey : notnull where TValue : ICollection, new() @@ -28,12 +82,6 @@ public static void RegisterCacheEntry(this Dictionary> source, out ComplexTypeSpec Key, out List Value) - { - Key = (ComplexTypeSpec)source.Key; - Value = source.Value; - } - public static string ToIdentifierCompatibleSubstring(this ITypeSymbol type) { if (type is IArrayTypeSymbol arrayType) @@ -64,5 +112,15 @@ public static string ToIdentifierCompatibleSubstring(this ITypeSymbol type) return sb.ToString(); } + + public static (string? Namespace, string DisplayString, string Name) GetTypeName(this ITypeSymbol type) + { + string? @namespace = type.ContainingNamespace is { IsGlobalNamespace: false } containingNamespace ? containingNamespace.ToDisplayString() : null; + string displayString = type.ToDisplayString(s_minimalDisplayFormat); + string name = (@namespace is null ? string.Empty : @namespace + ".") + displayString.Replace(".", "+"); + return (@namespace, displayString, name); + } + + public static string GetName(this ITypeSymbol type) => GetTypeName(type).Name; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs similarity index 96% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/KnownTypeSymbols.cs rename to src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs index e381dc9c7c43ee..07dae8689782e4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs @@ -11,7 +11,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record KnownTypeSymbols + internal sealed class KnownTypeSymbols { public CSharpCompilation Compilation { get; } @@ -37,7 +37,7 @@ internal sealed record KnownTypeSymbols public INamedTypeSymbol? OptionsConfigurationServiceCollectionExtensions { get; } public INamedTypeSymbol GenericIList_Unbound { get; } - public INamedTypeSymbol GenericICollection_Unbound { get; } + public INamedTypeSymbol? GenericICollection_Unbound { get; } public INamedTypeSymbol GenericICollection { get; } public INamedTypeSymbol GenericIEnumerable_Unbound { get; } public INamedTypeSymbol IEnumerable { get; } @@ -61,7 +61,8 @@ public KnownTypeSymbols(CSharpCompilation compilation) { Compilation = compilation; - // Primitives (needed because they are Microsoft.CodeAnalysis.SpecialType.None) + // Primitives + String = compilation.GetSpecialType(SpecialType.System_String); CultureInfo = compilation.GetBestTypeByMetadataName(typeof(CultureInfo)); DateOnly = compilation.GetBestTypeByMetadataName("System.DateOnly"); DateTimeOffset = compilation.GetBestTypeByMetadataName(typeof(DateTimeOffset)); @@ -103,7 +104,7 @@ public KnownTypeSymbols(CSharpCompilation compilation) // Used for type equivalency checks for unbound generics. The parameters of the types // retured by the Roslyn Get*Type* APIs are not unbound, so we construct unbound // generics to equal those corresponding to generic types in the input type graphs. - GenericICollection_Unbound = GenericICollection?.ConstructUnboundGenericType(); + GenericICollection_Unbound = GenericICollection.ConstructUnboundGenericType(); GenericIDictionary_Unbound = GenericIDictionary?.ConstructUnboundGenericType(); GenericIEnumerable_Unbound = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).ConstructUnboundGenericType(); GenericIList_Unbound = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IList_T).ConstructUnboundGenericType(); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs index 9cf59a120e1fdc..eb0ab086bcd588 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsBuilderConfigurationExtensions.cs @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { public sealed partial class ConfigurationBindingGenerator { - private sealed partial class Parser + internal sealed partial class Parser { private void ParseInvocation_OptionsBuilderExt(BinderInvocation invocation) { @@ -29,22 +29,17 @@ private void ParseInvocation_OptionsBuilderExt(BinderInvocation invocation) // This would violate generic type constraint; any such invocation could not have been included in the initial parser. Debug.Assert(typeSymbol?.IsValueType is not true); - if (GetTargetTypeForRootInvocation(typeSymbol, invocation.Location) is not ComplexTypeSpec typeSpec) - { - return; - } - if (targetMethod.Name is "Bind") { - ParseBindInvocation_OptionsBuilderExt(invocation, typeSpec); + ParseBindInvocation_OptionsBuilderExt(invocation, typeSymbol); } else if (targetMethod.Name is "BindConfiguration") { - ParseBindConfigurationInvocation(invocation, typeSpec); + ParseBindConfigurationInvocation(invocation, typeSymbol); } } - private void ParseBindInvocation_OptionsBuilderExt(BinderInvocation invocation, ComplexTypeSpec typeSpec) + private void ParseBindInvocation_OptionsBuilderExt(BinderInvocation invocation, ITypeSymbol? type) { IInvocationOperation operation = invocation.Operation!; IMethodSymbol targetMethod = operation.TargetMethod; @@ -58,22 +53,21 @@ private void ParseBindInvocation_OptionsBuilderExt(BinderInvocation invocation, return; } - MethodsToGen_Extensions_OptionsBuilder overload = paramCount switch + MethodsToGen overload = paramCount switch { - 2 => MethodsToGen_Extensions_OptionsBuilder.Bind_T, + 2 => MethodsToGen.OptionsBuilderExt_Bind_T, 3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) => - MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions, - _ => MethodsToGen_Extensions_OptionsBuilder.None + MethodsToGen.OptionsBuilderExt_Bind_T_BinderOptions, + _ => MethodsToGen.None }; - if (overload is not MethodsToGen_Extensions_OptionsBuilder.None && - TryRegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec)) + if (overload is not MethodsToGen.None) { - RegisterInvocation(overload, operation); + EnqueueTargetTypeForRootInvocation(type, overload, invocation); } } - private void ParseBindConfigurationInvocation(BinderInvocation invocation, ComplexTypeSpec typeSpec) + private void ParseBindConfigurationInvocation(BinderInvocation invocation, ITypeSymbol? type) { IMethodSymbol targetMethod = invocation.Operation.TargetMethod; ImmutableArray @params = targetMethod.Parameters; @@ -83,23 +77,41 @@ private void ParseBindConfigurationInvocation(BinderInvocation invocation, Compl if (paramCount is 3 && @params[1].Type.SpecialType is SpecialType.System_String && - SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) && - TryRegisterTypeForBindCoreMainGen(typeSpec)) + SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type)) { - RegisterInvocation(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation); + EnqueueTargetTypeForRootInvocation(type, MethodsToGen.OptionsBuilderExt_BindConfiguration_T_path_BinderOptions, invocation); } } - private void RegisterInvocation(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation) + private void RegisterInterceptor_OptionsBuilderExt(TypeParseInfo typeParseInfo, TypeSpec typeSpec) { - _sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload; - RegisterInterceptor(overload, operation); + MethodsToGen overload = typeParseInfo.BindingOverload; + Debug.Assert((MethodsToGen.OptionsBuilderExt_Any & overload) is not 0); + + if (typeSpec is not ComplexTypeSpec complexTypeSpec) + { + return; + } + + if ((MethodsToGen.OptionsBuilderExt_Bind & overload) is not 0) + { + if (!TryRegisterTypeForOverloadGen_ServiceCollectionExt(MethodsToGen.ServiceCollectionExt_Configure_T_name_BinderOptions, complexTypeSpec)) + { + return; + } + } + else if (!_helperInfoBuilder!.TryRegisterTypeForBindCoreMainGen(complexTypeSpec)) + { + return; + } + + _interceptorInfoBuilder.RegisterInterceptor(typeParseInfo.BindingOverload, typeParseInfo.BinderInvocation.Operation); // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource. - _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); + _helperInfoBuilder!.RegisterNamespace("Microsoft.Extensions.Options"); // Emitting refs to OptionsBuilder. - _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); + _helperInfoBuilder!.RegisterNamespace("Microsoft.Extensions.DependencyInjection"); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs index e86231f32e42ab..1ccef24bc6b71f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/OptionsConfigurationServiceCollectionExtensions.cs @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { public sealed partial class ConfigurationBindingGenerator { - private sealed partial class Parser + internal sealed partial class Parser { private void ParseInvocation_ServiceCollectionExt(BinderInvocation invocation) { @@ -30,11 +30,11 @@ private void ParseInvocation_ServiceCollectionExt(BinderInvocation invocation) return; } - MethodsToGen_Extensions_ServiceCollection overload; + MethodsToGen overload; if (paramCount is 2 && SymbolEqualityComparer.Default.Equals(_typeSymbols.IConfiguration, @params[1].Type)) { - overload = MethodsToGen_Extensions_ServiceCollection.Configure_T; + overload = MethodsToGen.ServiceCollectionExt_Configure_T; } else if (paramCount is 3) { @@ -44,12 +44,12 @@ private void ParseInvocation_ServiceCollectionExt(BinderInvocation invocation) if (secondParamType.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.IConfiguration, thirdParamType)) { - overload = MethodsToGen_Extensions_ServiceCollection.Configure_T_name; + overload = MethodsToGen.ServiceCollectionExt_Configure_T_name; } else if (SymbolEqualityComparer.Default.Equals(_typeSymbols.IConfiguration, secondParamType) && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, thirdParamType)) { - overload = MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions; + overload = MethodsToGen.ServiceCollectionExt_Configure_T_BinderOptions; } else { @@ -61,7 +61,7 @@ @params[1].Type.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.IConfiguration, @params[2].Type) && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[3].Type)) { - overload = MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions; + overload = MethodsToGen.ServiceCollectionExt_Configure_T_name_BinderOptions; } else { @@ -73,25 +73,34 @@ @params[1].Type.SpecialType is SpecialType.System_String && // This would violate generic type constraint; any such invocation could not have been included in the initial parser. Debug.Assert(typeSymbol?.IsValueType is not true); - if (GetTargetTypeForRootInvocation(typeSymbol, invocation.Location) is ComplexTypeSpec typeSpec && - TryRegisterTypeForMethodGen(overload, typeSpec)) + EnqueueTargetTypeForRootInvocation(typeSymbol, overload, invocation); + } + + private void RegisterInterceptor_ServiceCollectionExt(TypeParseInfo typeParseInfo, TypeSpec typeSpec) + { + MethodsToGen overload = typeParseInfo.BindingOverload; + + if (typeSpec is ComplexTypeSpec complexTypeSpec && + TryRegisterTypeForOverloadGen_ServiceCollectionExt(overload, complexTypeSpec)) { - RegisterInterceptor(overload, operation); + _interceptorInfoBuilder.RegisterInterceptor(overload, typeParseInfo.BinderInvocation.Operation); } } - private bool TryRegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, ComplexTypeSpec typeSpec) + private bool TryRegisterTypeForOverloadGen_ServiceCollectionExt(MethodsToGen overload, ComplexTypeSpec typeSpec) { - if (TryRegisterTypeForBindCoreMainGen(typeSpec)) + Debug.Assert((MethodsToGen.ServiceCollectionExt_Any & overload) is not 0); + + if (!_helperInfoBuilder!.TryRegisterTypeForBindCoreMainGen(typeSpec)) { - _sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload; - _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection"); - // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource, IConfigureOptions<>, ConfigureNamedOptions<>. - _sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options"); - return true; + return false; } - return false; + _interceptorInfoBuilder.MethodsToGen |= overload; + _helperInfoBuilder!.RegisterNamespace("Microsoft.Extensions.DependencyInjection"); + // Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource, IConfigureOptions<>, ConfigureNamedOptions<>. + _helperInfoBuilder!.RegisterNamespace("Microsoft.Extensions.Options"); + return true; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/BindingHelperInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/BindingHelperInfo.cs new file mode 100644 index 00000000000000..096c8410717ae7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/BindingHelperInfo.cs @@ -0,0 +1,237 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using SourceGenerators; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + public sealed record BindingHelperInfo + { + public required ImmutableEquatableArray Namespaces { get; init; } + public required bool EmitConfigurationKeyCaches { get; init; } + + public required MethodsToGen_CoreBindingHelper MethodsToGen { get; init; } + public required ImmutableEquatableArray? TypesForGen_BindCoreMain { get; init; } + public required ImmutableEquatableArray? TypesForGen_GetCore { get; init; } + public required ImmutableEquatableArray? TypesForGen_GetValueCore { get; init; } + public required ImmutableEquatableArray? TypesForGen_BindCore { get; init; } + public required ImmutableEquatableArray? TypesForGen_Initialize { get; init; } + public required ImmutableEquatableArray? TypesForGen_ParsePrimitive { get; init; } + + internal sealed class Builder(TypeIndex _typeIndex) + { + private readonly Dictionary _seenTransitiveTypes = new(); + + private MethodsToGen_CoreBindingHelper _methodsToGen; + private bool _emitConfigurationKeyCaches; + + private readonly Dictionary> _typesForGen = new(); + + private readonly SortedSet _namespaces = new() + { + "System", + "System.CodeDom.Compiler", + "System.Globalization", + "System.Runtime.CompilerServices", + "Microsoft.Extensions.Configuration", + }; + + public BindingHelperInfo ToIncrementalValue() + { + return new BindingHelperInfo + { + Namespaces = _namespaces.ToImmutableEquatableArray(), + EmitConfigurationKeyCaches = _emitConfigurationKeyCaches, + + MethodsToGen = _methodsToGen, + TypesForGen_GetCore = GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper.GetCore), + TypesForGen_BindCoreMain = GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper.BindCoreMain), + TypesForGen_GetValueCore = GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper.GetValueCore), + TypesForGen_BindCore = GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper.BindCore), + TypesForGen_Initialize = GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper.Initialize), + TypesForGen_ParsePrimitive = GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper.ParsePrimitive) + }; + + ImmutableEquatableArray? GetTypesForGen_CoreBindingHelper(MethodsToGen_CoreBindingHelper overload) + where TSpec : TypeSpec, IEquatable + { + _typesForGen.TryGetValue(overload, out HashSet? typesAsBase); + + if (typesAsBase is null) + { + return null; + } + + IEnumerable types = typeof(TSpec) == typeof(TypeSpec) + ? (HashSet)(object)typesAsBase + : typesAsBase.Select(t => (TSpec)t); + + return GetTypesForGen(types); + } + + static ImmutableEquatableArray GetTypesForGen(IEnumerable types) + where TSpec : TypeSpec, IEquatable => + types.ToImmutableEquatableArray(); + } + + public bool TryRegisterTypeForGetGen(TypeSpec type) + { + if (TryRegisterTransitiveTypesForMethodGen(type.TypeRef)) + { + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, type); + RegisterForGen_AsConfigWithChildrenHelper(); + return true; + } + + return false; + } + + public bool TryRegisterTypeForGetValueGen(TypeSpec typeSpec) + { + ParsableFromStringSpec effectiveType = (ParsableFromStringSpec)_typeIndex.GetEffectiveTypeSpec(typeSpec); + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec); + RegisterStringParsableTypeIfApplicable(effectiveType); + return true; + } + + public bool TryRegisterTypeForBindCoreMainGen(ComplexTypeSpec type) + { + if (TryRegisterTransitiveTypesForMethodGen(type.TypeRef)) + { + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, type); + RegisterForGen_AsConfigWithChildrenHelper(); + return true; + } + + return false; + } + + public bool TryRegisterTransitiveTypesForMethodGen(TypeRef typeRef) + { + return _seenTransitiveTypes.TryGetValue(typeRef, out bool isValid) + ? isValid + : (_seenTransitiveTypes[typeRef] = TryRegisterCore()); + + bool TryRegisterCore() + { + switch (_typeIndex.GetTypeSpec(typeRef)) + { + case NullableSpec nullableSpec: + { + return TryRegisterTransitiveTypesForMethodGen(nullableSpec.EffectiveTypeRef); + } + case ParsableFromStringSpec stringParsableSpec: + { + RegisterStringParsableTypeIfApplicable(stringParsableSpec); + return true; + } + case DictionarySpec dictionarySpec: + { + bool shouldRegister = _typeIndex.CanBindTo(typeRef) && + TryRegisterTransitiveTypesForMethodGen(dictionarySpec.KeyTypeRef) && + TryRegisterTransitiveTypesForMethodGen(dictionarySpec.ElementTypeRef) && + TryRegisterTypeForBindCoreGen(dictionarySpec); + + if (shouldRegister && dictionarySpec.InstantiationStrategy is CollectionInstantiationStrategy.LinqToDictionary) + { + _namespaces.Add("System.Linq"); + } + + return shouldRegister; + } + case CollectionSpec collectionSpec: + { + return TryRegisterTransitiveTypesForMethodGen(collectionSpec.ElementTypeRef) && + TryRegisterTypeForBindCoreGen(collectionSpec); + } + case ObjectSpec objectSpec: + { + // Base case to avoid stack overflow for recursive object graphs. + // Register all object types for gen; we need to throw runtime exceptions in some cases. + bool shouldRegister = true; + _seenTransitiveTypes.Add(typeRef, shouldRegister); + + // List is used in generated code as a temp holder for formatting + // an error for config properties that don't map to object properties. + _namespaces.Add("System.Collections.Generic"); + + if (_typeIndex.HasBindableMembers(objectSpec)) + { + foreach (PropertySpec property in objectSpec.Properties!) + { + TryRegisterTransitiveTypesForMethodGen(property.TypeRef); + + if (_typeIndex.GetTypeSpec(property.TypeRef) is ComplexTypeSpec) + { + RegisterForGen_AsConfigWithChildrenHelper(); + } + } + + bool registeredForBindCore = TryRegisterTypeForBindCoreGen(objectSpec); + Debug.Assert(registeredForBindCore); + + if (objectSpec is { InstantiationStrategy: ObjectInstantiationStrategy.ParameterizedConstructor, InitExceptionMessage: null }) + { + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.Initialize, objectSpec); + } + } + + return true; + } + default: + { + return true; + } + } + } + } + + public void RegisterNamespace(string @namespace) => _namespaces.Add(@namespace); + + private bool TryRegisterTypeForBindCoreGen(ComplexTypeSpec type) + { + if (_typeIndex.HasBindableMembers(type)) + { + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, type); + _emitConfigurationKeyCaches = true; + return true; + } + + return false; + } + + private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type) + { + if (!_typesForGen.TryGetValue(method, out HashSet? types)) + { + _typesForGen[method] = types = new HashSet(); + } + + if (types.Add(type)) + { + _methodsToGen |= method; + + if (type is { Namespace: string @namespace }) + { + _namespaces.Add(@namespace); + } + } + } + + private void RegisterStringParsableTypeIfApplicable(ParsableFromStringSpec type) + { + if (type.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue) + { + _methodsToGen |= MethodsToGen_CoreBindingHelper.ParsePrimitive; + RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.ParsePrimitive, type); + } + } + + private void RegisterForGen_AsConfigWithChildrenHelper() => _methodsToGen |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorInfo.cs new file mode 100644 index 00000000000000..999ed6514f99d7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorInfo.cs @@ -0,0 +1,202 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Text; +using SourceGenerators; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + public sealed record InterceptorInfo + { + public required MethodsToGen MethodsToGen { get; init; } + + public required ImmutableEquatableArray? ConfigBinder_Bind_instance { get; init; } + public required ImmutableEquatableArray? ConfigBinder_Bind_instance_BinderOptions { get; init; } + public required ImmutableEquatableArray? ConfigBinder_Bind_key_instance { get; init; } + + + public required ImmutableEquatableArray? ConfigBinder { get; init; } + public required ImmutableEquatableArray? OptionsBuilderExt { get; init; } + public required ImmutableEquatableArray? ServiceCollectionExt { get; init; } + + public IEnumerable? GetInfo(MethodsToGen interceptor) + { + Debug.Assert((MethodsToGen.ConfigBinder_Bind & interceptor) is 0); + + ImmutableEquatableArray? infoList; + if ((MethodsToGen.ConfigBinder_Any ^ MethodsToGen.ConfigBinder_Bind & interceptor) is not 0) + { + infoList = ConfigBinder; + } + else if ((MethodsToGen.OptionsBuilderExt_Any & interceptor) is not 0) + { + infoList = OptionsBuilderExt; + } + else + { + Debug.Assert((MethodsToGen.ServiceCollectionExt_Any & interceptor) is not 0); + infoList = ServiceCollectionExt; + } + + return infoList?.Where(i => i.Interceptor == interceptor); + } + + internal sealed class Builder + { + private TypedInterceptorInfoBuildler? _configBinder_InfoBuilder_Bind_instance; + private TypedInterceptorInfoBuildler? _configBinder_InfoBuilder_Bind_instance_BinderOptions; + private TypedInterceptorInfoBuildler? _configBinder_InfoBuilder_Bind_key_instance; + + private List? _interceptors_configBinder; + private List? _interceptors_OptionsBuilderExt; + private List? _interceptors_serviceCollectionExt; + + public MethodsToGen MethodsToGen { get; set; } + + public void RegisterInterceptor_ConfigBinder_Bind(MethodsToGen overload, ComplexTypeSpec type, IInvocationOperation invocation) + { + Debug.Assert((MethodsToGen.ConfigBinder_Bind & overload) is not 0); + + switch (overload) + { + case MethodsToGen.ConfigBinder_Bind_instance: + RegisterInterceptor(ref _configBinder_InfoBuilder_Bind_instance); + break; + case MethodsToGen.ConfigBinder_Bind_instance_BinderOptions: + RegisterInterceptor(ref _configBinder_InfoBuilder_Bind_instance_BinderOptions); + break; + case MethodsToGen.ConfigBinder_Bind_key_instance: + RegisterInterceptor(ref _configBinder_InfoBuilder_Bind_key_instance); + break; + } + + MethodsToGen |= overload; + + void RegisterInterceptor(ref TypedInterceptorInfoBuildler? infoBuilder) + { + infoBuilder ??= new TypedInterceptorInfoBuildler(); + infoBuilder.RegisterInterceptor(overload, type, invocation); + } + } + + public void RegisterInterceptor(MethodsToGen overload, IInvocationOperation operation) + { + Debug.Assert((MethodsToGen.ConfigBinder_Bind & overload) is 0); + + if ((MethodsToGen.ConfigBinder_Any ^ MethodsToGen.ConfigBinder_Bind & overload) is not 0) + { + RegisterInterceptor(ref _interceptors_configBinder); + } + else if ((MethodsToGen.OptionsBuilderExt_Any & overload) is not 0) + { + RegisterInterceptor(ref _interceptors_OptionsBuilderExt); + } + else + { + Debug.Assert((MethodsToGen.ServiceCollectionExt_Any & overload) is not 0); + RegisterInterceptor(ref _interceptors_serviceCollectionExt); + } + + MethodsToGen |= overload; + + void RegisterInterceptor(ref List? infoList) + { + infoList ??= new List(); + infoList.Add(new InvocationLocationInfo(overload, operation)); + } + } + + public InterceptorInfo ToIncrementalValue() => + new InterceptorInfo + { + MethodsToGen = MethodsToGen, + + ConfigBinder = _interceptors_configBinder?.ToImmutableEquatableArray(), + OptionsBuilderExt = _interceptors_OptionsBuilderExt?.ToImmutableEquatableArray(), + ServiceCollectionExt = _interceptors_serviceCollectionExt?.ToImmutableEquatableArray(), + + ConfigBinder_Bind_instance = _configBinder_InfoBuilder_Bind_instance?.ToIncrementalValue(), + ConfigBinder_Bind_instance_BinderOptions = _configBinder_InfoBuilder_Bind_instance_BinderOptions?.ToIncrementalValue(), + ConfigBinder_Bind_key_instance = _configBinder_InfoBuilder_Bind_key_instance?.ToIncrementalValue(), + }; + } + } + + internal sealed class TypedInterceptorInfoBuildler + { + private readonly Dictionary _invocationInfoBuilderCache = new(); + + public void RegisterInterceptor(MethodsToGen overload, ComplexTypeSpec type, IInvocationOperation invocation) + { + if (!_invocationInfoBuilderCache.TryGetValue(type, out TypedInterceptorInvocationInfo.Builder? invocationInfoBuilder)) + { + _invocationInfoBuilderCache[type] = invocationInfoBuilder = new TypedInterceptorInvocationInfo.Builder(overload, type); + } + + invocationInfoBuilder.RegisterInvocation(invocation); + } + + public ImmutableEquatableArray? ToIncrementalValue() => + _invocationInfoBuilderCache.Values + .Select(b => b.ToIncrementalValue()) + .ToImmutableEquatableArray(); + } + + public sealed record TypedInterceptorInvocationInfo(ComplexTypeSpec TargetType, ImmutableEquatableArray Locations) + { + public sealed class Builder(MethodsToGen Overload, ComplexTypeSpec TargetType) + { + private readonly List _infoList = new(); + + public void RegisterInvocation(IInvocationOperation invocation) => + _infoList.Add(new InvocationLocationInfo(Overload, invocation)); + + public TypedInterceptorInvocationInfo ToIncrementalValue() => new( + TargetType, + Locations: _infoList.ToImmutableEquatableArray()); + } + } + + public sealed record InvocationLocationInfo + { + public InvocationLocationInfo(MethodsToGen interceptor, IInvocationOperation invocation) + { + Debug.Assert(BinderInvocation.IsBindingOperation(invocation)); + + if (invocation.Syntax is not InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax memberAccessExprSyntax }) + { + const string InvalidInvocationErrMsg = "The invocation should have been validated upstream when selecting invocations to emit interceptors for."; + throw new ArgumentException(InvalidInvocationErrMsg, nameof(invocation)); + } + + SyntaxTree operationSyntaxTree = invocation.Syntax.SyntaxTree; + TextSpan memberNameSpan = memberAccessExprSyntax.Name.Span; + FileLinePositionSpan linePosSpan = operationSyntaxTree.GetLineSpan(memberNameSpan); + + Interceptor = interceptor; + LineNumber = linePosSpan.StartLinePosition.Line + 1; + CharacterNumber = linePosSpan.StartLinePosition.Character + 1; + FilePath = GetInterceptorFilePath(); + + // Use the same logic used by the interceptors API for resolving the source mapped value of a path. + // https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064 + string GetInterceptorFilePath() + { + SourceReferenceResolver? sourceReferenceResolver = invocation.SemanticModel?.Compilation.Options.SourceReferenceResolver; + return sourceReferenceResolver?.NormalizePath(operationSyntaxTree.FilePath, baseFilePath: null) ?? operationSyntaxTree.FilePath; + } + } + + public MethodsToGen Interceptor { get; } + public string FilePath { get; } + public int LineNumber { get; } + public int CharacterNumber { get; } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorLocationInfo.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorLocationInfo.cs deleted file mode 100644 index 441acbe6a7444f..00000000000000 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/InterceptorLocationInfo.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections; -using System.Collections.Generic; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Operations; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration -{ - internal sealed record InterceptorLocationInfo - { - public InterceptorLocationInfo(IInvocationOperation operation) - { - MemberAccessExpressionSyntax memberAccessExprSyntax = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operation.Syntax).Expression); - SyntaxTree operationSyntaxTree = operation.Syntax.SyntaxTree; - TextSpan memberNameSpan = memberAccessExprSyntax.Name.Span; - FileLinePositionSpan linePosSpan = operationSyntaxTree.GetLineSpan(memberNameSpan); - - LineNumber = linePosSpan.StartLinePosition.Line + 1; - CharacterNumber = linePosSpan.StartLinePosition.Character + 1; - FilePath = GetInterceptorFilePath(); - - // Use the same logic used by the interceptors API for resolving the source mapped value of a path. - // https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064 - string GetInterceptorFilePath() - { - SourceReferenceResolver? sourceReferenceResolver = operation.SemanticModel?.Compilation.Options.SourceReferenceResolver; - return sourceReferenceResolver?.NormalizePath(operationSyntaxTree.FilePath, baseFilePath: null) ?? operationSyntaxTree.FilePath; - } - } - - public string FilePath { get; } - public int LineNumber { get; } - public int CharacterNumber { get; } - } - - internal sealed record ConfigurationBinderInterceptorInfo - { - private OverloadInterceptorInfo? _bind_Instance; - private OverloadInterceptorInfo? _bind_instance_BinderOptions; - private OverloadInterceptorInfo? _bind_key_instance; - - public void RegisterOverloadInfo(MethodsToGen_ConfigurationBinder overload, TypeSpec type, IInvocationOperation operation) - { - OverloadInterceptorInfo overloadInfo = DetermineOverload(overload, initIfNull: true); - overloadInfo.RegisterLocationInfo(type, operation); - } - - public OverloadInterceptorInfo GetOverloadInfo(MethodsToGen_ConfigurationBinder overload) => - DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentOutOfRangeException(nameof(overload)); - - private OverloadInterceptorInfo? DetermineOverload(MethodsToGen_ConfigurationBinder overload, bool initIfNull) - { - return overload switch - { - MethodsToGen_ConfigurationBinder.Bind_instance => InitIfNull(ref _bind_Instance), - MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => InitIfNull(ref _bind_instance_BinderOptions), - MethodsToGen_ConfigurationBinder.Bind_key_instance => InitIfNull(ref _bind_key_instance), - _ => throw new InvalidOperationException(nameof(overload)), - }; - - OverloadInterceptorInfo InitIfNull(ref OverloadInterceptorInfo? info) - { - if (initIfNull) - { - info ??= new OverloadInterceptorInfo(); - } - - return info; - } - } - } - - internal sealed record OverloadInterceptorInfo : IEnumerable>> - { - private readonly Dictionary> _typeInterceptionInfo = new(); - - public void RegisterLocationInfo(TypeSpec type, IInvocationOperation operation) => - _typeInterceptionInfo.RegisterCacheEntry(type, new InterceptorLocationInfo(operation)); - - public IEnumerator>> GetEnumerator() => _typeInterceptionInfo.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } -} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs index effd550482595d..dc5b03087ac87a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs @@ -3,10 +3,11 @@ using System.Diagnostics; using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal abstract record MemberSpec + public abstract record MemberSpec { public MemberSpec(ISymbol member) { @@ -18,7 +19,7 @@ public MemberSpec(ISymbol member) public string Name { get; } public string DefaultValueExpr { get; protected set; } - public required TypeSpec Type { get; init; } + public required TypeRef TypeRef { get; init; } public required string ConfigurationKeyName { get; init; } public abstract bool CanGet { get; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/ParameterSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/ParameterSpec.cs index 0f17a6247f74d2..62c781e1f1631f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/ParameterSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/ParameterSpec.cs @@ -6,7 +6,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record ParameterSpec : MemberSpec + public sealed record ParameterSpec : MemberSpec { public ParameterSpec(IParameterSymbol parameter) : base(parameter) { @@ -14,7 +14,7 @@ public ParameterSpec(IParameterSymbol parameter) : base(parameter) if (parameter.HasExplicitDefaultValue) { - string formatted = SymbolDisplay.FormatPrimitive(parameter.ExplicitDefaultValue, quoteStrings: true, useHexadecimalNumbers: false); + string formatted = SymbolDisplay.FormatPrimitive(parameter.ExplicitDefaultValue!, quoteStrings: true, useHexadecimalNumbers: false); if (formatted is not "null") { DefaultValueExpr = formatted; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs index 4e9c468c4e3352..443e39d32e4933 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs @@ -5,7 +5,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record PropertySpec : MemberSpec + public sealed record PropertySpec : MemberSpec { public PropertySpec(IPropertySymbol property) : base(property) { @@ -28,7 +28,5 @@ public PropertySpec(IPropertySymbol property) : base(property) public override bool CanGet { get; } public override bool CanSet { get; } - - public bool ShouldBindTo => CanGet || CanSet; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/MethodsToGen.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/MethodsToGen.cs index 6165a3e6d46dcb..af2a33fa6c2f80 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/MethodsToGen.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/MethodsToGen.cs @@ -16,137 +16,130 @@ public enum MethodsToGen_CoreBindingHelper Initialize = 0x10, HasValueOrChildren = 0x20, AsConfigWithChildren = 0x40, + ParsePrimitive = 0x80, } /// /// Methods on Microsoft.Extensions.Configuration.ConfigurationBinder /// [Flags] - internal enum MethodsToGen_ConfigurationBinder + public enum MethodsToGen { None = 0x0, + Any = ConfigBinder_Any | OptionsBuilderExt_Any | ServiceCollectionExt_Any, + #region IConfiguration ext. method overloads: 0x1 - 0x400 /// /// Bind(IConfiguration, object?). /// - Bind_instance = 0x1, + ConfigBinder_Bind_instance = 0x1, /// /// Bind(IConfiguration, object?, Action?). /// - Bind_instance_BinderOptions = 0x2, + ConfigBinder_Bind_instance_BinderOptions = 0x2, /// /// Bind(IConfiguration, string, object?). /// - Bind_key_instance = 0x4, + ConfigBinder_Bind_key_instance = 0x4, /// /// Get(IConfiguration). /// - Get_T = 0x8, + ConfigBinder_Get_T = 0x8, /// /// Get(IConfiguration, Action?). /// - Get_T_BinderOptions = 0x10, + ConfigBinder_Get_T_BinderOptions = 0x10, /// /// Get(IConfiguration, Type). /// - Get_TypeOf = 0x20, + ConfigBinder_Get_TypeOf = 0x20, /// /// Get(IConfiguration, Type, Action?). /// - Get_TypeOf_BinderOptions = 0x40, + ConfigBinder_Get_TypeOf_BinderOptions = 0x40, /// /// GetValue(IConfiguration, Type, string). /// - GetValue_TypeOf_key = 0x80, + ConfigBinder_GetValue_TypeOf_key = 0x80, /// /// GetValue(IConfiguration, Type, object?). /// - GetValue_TypeOf_key_defaultValue = 0x100, + ConfigBinder_GetValue_TypeOf_key_defaultValue = 0x100, /// /// GetValue(IConfiguration, string). /// - GetValue_T_key = 0x200, + ConfigBinder_GetValue_T_key = 0x200, /// /// GetValue(IConfiguration, string, T). /// - GetValue_T_key_defaultValue = 0x400, + ConfigBinder_GetValue_T_key_defaultValue = 0x400, // Method groups - Bind = Bind_instance | Bind_instance_BinderOptions | Bind_key_instance, - Get = Get_T | Get_T_BinderOptions | Get_TypeOf | Get_TypeOf_BinderOptions, - GetValue = GetValue_T_key | GetValue_T_key_defaultValue | GetValue_TypeOf_key | GetValue_TypeOf_key_defaultValue, + ConfigBinder_Bind = ConfigBinder_Bind_instance | ConfigBinder_Bind_instance_BinderOptions | ConfigBinder_Bind_key_instance, + ConfigBinder_Get = ConfigBinder_Get_T | ConfigBinder_Get_T_BinderOptions | ConfigBinder_Get_TypeOf | ConfigBinder_Get_TypeOf_BinderOptions, + ConfigBinder_GetValue = ConfigBinder_GetValue_T_key | ConfigBinder_GetValue_T_key_defaultValue | ConfigBinder_GetValue_TypeOf_key | ConfigBinder_GetValue_TypeOf_key_defaultValue, - Any = Bind | Get | GetValue, - } - - [Flags] - internal enum MethodsToGen_Extensions_OptionsBuilder - { - None = 0x0, + ConfigBinder_Any = ConfigBinder_Bind | ConfigBinder_Get | ConfigBinder_GetValue, + #endregion ConfigurationBinder ext. method overloads. + #region OptionsBuilder ext. method overloads: 0x800 - 0x2000 /// /// Bind(OptionsBuilder, IConfiguration). /// - Bind_T = 0x1, + OptionsBuilderExt_Bind_T = 0x800, /// /// Bind(OptionsBuilder, IConfiguration, Action?). /// - Bind_T_BinderOptions = 0x2, + OptionsBuilderExt_Bind_T_BinderOptions = 0x1000, /// /// BindConfiguration(OptionsBuilder, string, Action?). /// - BindConfiguration_T_path_BinderOptions = 0x4, + OptionsBuilderExt_BindConfiguration_T_path_BinderOptions = 0x2000, // Method group. BindConfiguration_T is its own method group. - Bind = Bind_T | Bind_T_BinderOptions, - - BindConfiguration = BindConfiguration_T_path_BinderOptions, + OptionsBuilderExt_Bind = OptionsBuilderExt_Bind_T | OptionsBuilderExt_Bind_T_BinderOptions, - Any = Bind | BindConfiguration, - } + OptionsBuilderExt_BindConfiguration = OptionsBuilderExt_BindConfiguration_T_path_BinderOptions, - /// - /// Methods on Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions - /// - [Flags] - public enum MethodsToGen_Extensions_ServiceCollection - { - None = 0x0, + OptionsBuilderExt_Any = OptionsBuilderExt_Bind | OptionsBuilderExt_BindConfiguration, + #endregion OptionsBuilder ext. method overloads. + #region IServiceCollection ext. method overloads: 0x4000 - 0x20000 /// /// Configure(IServiceCollection, IConfiguration). /// - Configure_T = 0x1, + ServiceCollectionExt_Configure_T = 0x4000, /// /// Configure(IServiceCollection, string, IConfiguration). /// - Configure_T_name = 0x2, + ServiceCollectionExt_Configure_T_name = 0x8000, /// /// Configure(IServiceCollection, IConfiguration, Action?). /// - Configure_T_BinderOptions = 0x4, + ServiceCollectionExt_Configure_T_BinderOptions = 0x10000, /// /// Configure(IServiceCollection, string, IConfiguration, Action?). /// - Configure_T_name_BinderOptions = 0x8, + ServiceCollectionExt_Configure_T_name_BinderOptions = 0x20000, - Configure = Configure_T | Configure_T_name | Configure_T_BinderOptions | Configure_T_name_BinderOptions, + ServiceCollectionExt_Configure = ServiceCollectionExt_Configure_T | ServiceCollectionExt_Configure_T_name | ServiceCollectionExt_Configure_T_BinderOptions | ServiceCollectionExt_Configure_T_name_BinderOptions, - Any = Configure, + ServiceCollectionExt_Any = ServiceCollectionExt_Configure, + #endregion IServiceCollection ext. method overloads: 0x4000 - 0x20000 } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs index 760d57b1dcc888..4f57316429e2b1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/SourceGenerationSpec.cs @@ -1,31 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record SourceGenerationSpec + public sealed record SourceGenerationSpec { - public Dictionary> InterceptionInfo { get; } = new(); - public ConfigurationBinderInterceptorInfo InterceptionInfo_ConfigBinder { get; } = new(); - - public Dictionary> TypesForGen_CoreBindingHelper_Methods { get; } = new(); - - public HashSet PrimitivesForHelperGen { get; } = new(); - public HashSet Namespaces { get; } = new() - { - "System", - "System.CodeDom.Compiler", - "System.Globalization", - "System.Runtime.CompilerServices", - "Microsoft.Extensions.Configuration", - }; - - public MethodsToGen_CoreBindingHelper MethodsToGen_CoreBindingHelper { get; set; } - public MethodsToGen_ConfigurationBinder MethodsToGen_ConfigurationBinder { get; set; } - public MethodsToGen_Extensions_OptionsBuilder MethodsToGen_OptionsBuilderExt { get; set; } - public MethodsToGen_Extensions_ServiceCollection MethodsToGen_ServiceCollectionExt { get; set; } + public required InterceptorInfo InterceptorInfo { get; init; } + public required BindingHelperInfo BindingHelperInfo { get; init; } + public required ImmutableEquatableArray ConfigTypes { get; init; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/TypeIndex.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/TypeIndex.cs new file mode 100644 index 00000000000000..5b59577b392921 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/TypeIndex.cs @@ -0,0 +1,122 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using SourceGenerators; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + internal sealed class TypeIndex(IEnumerable typeSpecs) + { + private readonly Dictionary _index = typeSpecs.ToDictionary(spec => spec.TypeRef); + + public bool CanBindTo(TypeRef typeRef) => GetEffectiveTypeSpec(typeRef) switch + { + SimpleTypeSpec => true, + ComplexTypeSpec complexTypeSpec => CanInstantiate(complexTypeSpec) || HasBindableMembers(complexTypeSpec), + _ => throw new InvalidOperationException(), + }; + + public bool CanInstantiate(ComplexTypeSpec typeSpec) => typeSpec switch + { + ObjectSpec objectSpec => objectSpec is { InstantiationStrategy: not ObjectInstantiationStrategy.None, InitExceptionMessage: null }, + DictionarySpec dictionarySpec => KeyIsSupported(dictionarySpec), + CollectionSpec collectionSpec => CanBindTo(collectionSpec.ElementTypeRef), + _ => throw new InvalidOperationException(), + }; + + public bool HasBindableMembers(ComplexTypeSpec typeSpec) => + typeSpec switch + { + ObjectSpec objectSpec => objectSpec.Properties?.Any(ShouldBindTo) is true, + DictionarySpec dictSpec => KeyIsSupported(dictSpec) && CanBindTo(dictSpec.ElementTypeRef), + CollectionSpec collectionSpec => CanBindTo(collectionSpec.ElementTypeRef), + _ => throw new InvalidOperationException(), + }; + + public bool ShouldBindTo(PropertySpec property) + { + TypeSpec propTypeSpec = GetEffectiveTypeSpec(property.TypeRef); + return IsAccessible() && !IsCollectionAndCannotOverride() && !IsDictWithUnsupportedKey(); + + bool IsAccessible() => property.CanGet || property.CanSet; + + bool IsDictWithUnsupportedKey() => propTypeSpec is DictionarySpec dictionarySpec && !KeyIsSupported(dictionarySpec); + + bool IsCollectionAndCannotOverride() => !property.CanSet && + propTypeSpec is CollectionWithCtorInitSpec + { + InstantiationStrategy: CollectionInstantiationStrategy.CopyConstructor or CollectionInstantiationStrategy.LinqToDictionary + }; + } + + public TypeSpec GetEffectiveTypeSpec(TypeRef typeRef) + { + TypeSpec typeSpec = GetTypeSpec(typeRef); + return GetEffectiveTypeSpec(typeSpec); + } + + public TypeSpec GetEffectiveTypeSpec(TypeSpec typeSpec) + { + TypeRef effectiveRef = typeSpec.EffectiveTypeRef; + TypeSpec effectiveSpec = effectiveRef == typeSpec.TypeRef ? typeSpec : _index[effectiveRef]; + return effectiveSpec; + } + + public TypeSpec GetTypeSpec(TypeRef typeRef) => _index[typeRef]; + + public string GetInstantiationTypeDisplayString(CollectionWithCtorInitSpec type) + { + CollectionInstantiationConcreteType concreteType = type.InstantiationConcreteType; + return concreteType is CollectionInstantiationConcreteType.Self + ? type.DisplayString + : GetGenericTypeDisplayString(type, concreteType); + } + + public string GetPopulationCastTypeDisplayString(CollectionWithCtorInitSpec type) + { + CollectionPopulationCastType castType = type.PopulationCastType; + Debug.Assert(castType is not CollectionPopulationCastType.NotApplicable); + return GetGenericTypeDisplayString(type, castType); + } + + public string GetGenericTypeDisplayString(CollectionWithCtorInitSpec type, Enum genericProxyTypeName) + { + string proxyTypeNameStr = genericProxyTypeName.ToString(); + string elementTypeDisplayString = GetTypeSpec(type.ElementTypeRef).DisplayString; + + if (type is EnumerableSpec) + { + return $"{proxyTypeNameStr}<{elementTypeDisplayString}>"; + } + + string keyTypeDisplayString = GetTypeSpec(((DictionarySpec)type).KeyTypeRef).DisplayString; + return $"{proxyTypeNameStr}<{keyTypeDisplayString}, {elementTypeDisplayString}>"; + } + + public bool KeyIsSupported(DictionarySpec typeSpec) => + // Only types that are parsable from string are supported. + // Nullable keys not allowed; that would cause us to emit + // code that violates dictionary key notnull constraint. + GetTypeSpec(typeSpec.KeyTypeRef) is ParsableFromStringSpec; + + public static string GetConfigKeyCacheFieldName(ObjectSpec type) => $"s_configKeys_{type.IdentifierCompatibleSubstring}"; + + public static string GetParseMethodName(ParsableFromStringSpec type) + { + Debug.Assert(type.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue); + + string displayString = type.DisplayString; + + string parseMethod = type.StringParsableTypeKind is StringParsableTypeKind.ByteArray + ? "ParseByteArray" + // MinimalDisplayString.Length is certainly > 2. + : $"Parse{(char.ToUpper(displayString[0]) + displayString.Substring(1)).Replace(".", "")}"; + + return parseMethod; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs index f565d245cc5502..f891328f77af7c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/CollectionSpec.cs @@ -2,48 +2,67 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal abstract record CollectionSpec : ComplexTypeSpec { - public CollectionSpec(ITypeSymbol type) : base(type) { } + protected CollectionSpec(ITypeSymbol type) : base(type) { } - public sealed override bool CanInstantiate => TypeToInstantiate?.CanInstantiate ?? InstantiationStrategy is not InstantiationStrategy.None; + public required TypeRef ElementTypeRef { get; init; } - public required TypeSpec ElementType { get; init; } + } + + internal abstract record CollectionWithCtorInitSpec : CollectionSpec + { + protected CollectionWithCtorInitSpec(ITypeSymbol type) : base(type) { } - public required CollectionPopulationStrategy PopulationStrategy { get; init; } + public required CollectionInstantiationStrategy InstantiationStrategy { get; init; } - public required CollectionSpec? TypeToInstantiate { get; init; } + public required CollectionInstantiationConcreteType InstantiationConcreteType { get; init; } - public required CollectionSpec? PopulationCastType { get; init; } + public required CollectionPopulationCastType PopulationCastType { get; init; } } - internal sealed record EnumerableSpec : CollectionSpec + internal sealed record ArraySpec : CollectionSpec { - public EnumerableSpec(ITypeSymbol type) : base(type) { } - - public override TypeSpecKind SpecKind => TypeSpecKind.Enumerable; + public ArraySpec(ITypeSymbol type) : base(type) { } + } - public override bool HasBindableMembers => PopulationStrategy is not CollectionPopulationStrategy.Unknown && ElementType.CanBindTo; + internal sealed record EnumerableSpec : CollectionWithCtorInitSpec + { + public EnumerableSpec(ITypeSymbol type) : base(type) { } } - internal sealed record DictionarySpec : CollectionSpec + internal sealed record DictionarySpec : CollectionWithCtorInitSpec { public DictionarySpec(INamedTypeSymbol type) : base(type) { } - public override TypeSpecKind SpecKind => TypeSpecKind.Dictionary; + public required TypeRef KeyTypeRef { get; init; } + } - public override bool HasBindableMembers => PopulationStrategy is not CollectionPopulationStrategy.Unknown; + internal enum CollectionInstantiationStrategy + { + NotApplicable = 0, + ParameterlessConstructor = 1, + CopyConstructor = 2, + LinqToDictionary = 3, + } - public required ParsableFromStringSpec KeyType { get; init; } + internal enum CollectionInstantiationConcreteType + { + Self = 0, + Dictionary = 1, + List = 2, + HashSet = 3, } - internal enum CollectionPopulationStrategy + internal enum CollectionPopulationCastType { - Unknown = 0, - Add = 1, - Cast_Then_Add = 2, + NotApplicable = 0, + IDictionary = 1, + ICollection = 2, + ISet = 3, } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs deleted file mode 100644 index da5a5130141a53..00000000000000 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ComplexTypeSpec.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.CodeAnalysis; - -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration -{ - internal abstract record ComplexTypeSpec : TypeSpec - { - public ComplexTypeSpec(ITypeSymbol type) : base(type) { } - - public InstantiationStrategy InstantiationStrategy { get; set; } - - public sealed override bool CanBindTo => CanInstantiate || HasBindableMembers; - - public sealed override TypeSpec EffectiveType => this; - - public abstract bool HasBindableMembers { get; } - } - - internal enum InstantiationStrategy - { - None = 0, - ParameterlessConstructor = 1, - ParameterizedConstructor = 2, - ToEnumerableMethod = 3, - Array = 4, - } -} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/NullableSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/NullableSpec.cs deleted file mode 100644 index 3de6d7d465ad98..00000000000000 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/NullableSpec.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.CodeAnalysis; - -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration -{ - internal sealed record NullableSpec : TypeSpec - { - private readonly TypeSpec _underlyingType; - - public NullableSpec(ITypeSymbol type, TypeSpec underlyingType) : base(type) => _underlyingType = underlyingType; - - public override bool CanBindTo => _underlyingType.CanBindTo; - - public override bool CanInstantiate => _underlyingType.CanInstantiate; - - public override TypeSpecKind SpecKind => TypeSpecKind.Nullable; - - public override TypeSpec EffectiveType => _underlyingType; - } -} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs index f6978fa9cf470a..abc01258d4190c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/ObjectSpec.cs @@ -1,27 +1,39 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; -using System.Linq; using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal sealed record ObjectSpec : ComplexTypeSpec + public sealed record ObjectSpec : ComplexTypeSpec { - public ObjectSpec(INamedTypeSymbol type) : base(type) { } - - public override TypeSpecKind SpecKind => TypeSpecKind.Object; - - public override bool HasBindableMembers => Properties.Values.Any(p => p.ShouldBindTo); - - public override bool CanInstantiate => InstantiationStrategy is not InstantiationStrategy.None && InitExceptionMessage is null; - - public Dictionary Properties { get; } = new(StringComparer.OrdinalIgnoreCase); - - public List ConstructorParameters { get; } = new(); + public ObjectSpec( + INamedTypeSymbol type, + ObjectInstantiationStrategy instantiationStrategy, + ImmutableEquatableArray? properties, + ImmutableEquatableArray? constructorParameters, + string? initExceptionMessage) : base(type) + { + InstantiationStrategy = instantiationStrategy; + Properties = properties; + ConstructorParameters = constructorParameters; + InitExceptionMessage = initExceptionMessage; + } + + public ObjectInstantiationStrategy InstantiationStrategy { get; } + + public ImmutableEquatableArray? Properties { get; } + + public ImmutableEquatableArray? ConstructorParameters { get; } + + public string? InitExceptionMessage { get; } + } - public string? InitExceptionMessage { get; set; } + public enum ObjectInstantiationStrategy + { + None = 0, + ParameterlessConstructor = 1, + ParameterizedConstructor = 2, } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs index 2dfe08dc5f547a..70c7a8042e0359 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/SimpleTypeSpec.cs @@ -1,55 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics; using Microsoft.CodeAnalysis; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal abstract record SimpleTypeSpec : TypeSpec + public abstract record SimpleTypeSpec : TypeSpec { public SimpleTypeSpec(ITypeSymbol type) : base(type) { } - - public sealed override bool CanBindTo => true; - - public sealed override TypeSpec EffectiveType => this; - - public sealed override bool CanInstantiate => true; } internal sealed record ConfigurationSectionSpec : SimpleTypeSpec { public ConfigurationSectionSpec(ITypeSymbol type) : base(type) { } - - public override TypeSpecKind SpecKind => TypeSpecKind.IConfigurationSection; } - internal sealed record ParsableFromStringSpec : SimpleTypeSpec + public sealed record ParsableFromStringSpec : SimpleTypeSpec { public ParsableFromStringSpec(ITypeSymbol type) : base(type) { } - public override TypeSpecKind SpecKind => TypeSpecKind.ParsableFromString; - public required StringParsableTypeKind StringParsableTypeKind { get; init; } - - private string? _parseMethodName; - public string ParseMethodName - { - get - { - Debug.Assert(StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue); - - _parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray - ? "ParseByteArray" - // MinimalDisplayString.Length is certainly > 2. - : $"Parse{(char.ToUpper(DisplayString[0]) + DisplayString.Substring(1)).Replace(".", "")}"; - - return _parseMethodName; - } - } } - internal enum StringParsableTypeKind + public enum StringParsableTypeKind { None = 0, diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs index 651a40639f0ced..1c243ae1cdc7c1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs @@ -3,27 +3,26 @@ using System.Diagnostics; using Microsoft.CodeAnalysis; +using SourceGenerators; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { [DebuggerDisplay("Name={DisplayString}, Kind={SpecKind}")] - internal abstract record TypeSpec + public abstract record TypeSpec { - private static readonly SymbolDisplayFormat s_minimalDisplayFormat = new SymbolDisplayFormat( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes); - public TypeSpec(ITypeSymbol type) { - Namespace = type.ContainingNamespace?.ToDisplayString(); - DisplayString = type.ToDisplayString(s_minimalDisplayFormat); - Name = (Namespace is null ? string.Empty : Namespace + ".") + DisplayString.Replace(".", "+"); + TypeRef = new TypeRef(type); + EffectiveTypeRef = TypeRef; // Overriden by NullableSpec. + (Namespace, DisplayString, Name) = type.GetTypeName(); IdentifierCompatibleSubstring = type.ToIdentifierCompatibleSubstring(); IsValueType = type.IsValueType; } + public TypeRef TypeRef { get; } + + public TypeRef EffectiveTypeRef { get; protected init; } + public string Name { get; } public string DisplayString { get; } @@ -33,24 +32,35 @@ public TypeSpec(ITypeSymbol type) public string? Namespace { get; } public bool IsValueType { get; } + } - public abstract TypeSpecKind SpecKind { get; } + public abstract record ComplexTypeSpec : TypeSpec + { + protected ComplexTypeSpec(ITypeSymbol type) : base(type) { } + } - public abstract bool CanBindTo { get; } + internal sealed record NullableSpec : TypeSpec + { + public NullableSpec(ITypeSymbol type, TypeRef underlyingTypeRef) : base(type) => + EffectiveTypeRef = underlyingTypeRef; + } - public abstract bool CanInstantiate { get; } + internal sealed record UnsupportedTypeSpec : TypeSpec + { + public UnsupportedTypeSpec(ITypeSymbol type) : base(type) { } - public abstract TypeSpec EffectiveType { get; } + public required NotSupportedReason NotSupportedReason { get; init; } } - internal enum TypeSpecKind + public enum NotSupportedReason { - Unknown = 0, - ParsableFromString = 1, - Object = 2, - Enumerable = 3, - Dictionary = 4, - IConfigurationSection = 5, - Nullable = 6, + UnknownType = 1, + MissingPublicInstanceConstructor = 2, + CollectionNotSupported = 3, + DictionaryKeyNotSupported = 4, + ElementTypeNotSupported = 5, + MultipleParameterizedConstructors = 6, + MultiDimArraysNotSupported = 7, + NullableUnderlyingTypeNotSupported = 8, } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index ddd52c68b99892..ea4fba79cbc465 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -37,7 +37,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #endregion IConfiguration extensions. #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" }); + private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "ICustomDictionary", "ICustomCollection", "IReadOnlyList", "UnsupportedIReadOnlyDictionaryUnsupported", "IReadOnlyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { @@ -85,28 +85,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance.Add(ParseInt(value, () => section.Path)); - } - } - } - - public static void BindCore(IConfiguration configuration, ref ICollection instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance.Add(ParseInt(value, () => section.Path)); - } - } - } - public static void BindCore(IConfiguration configuration, ref IReadOnlyList instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { if (instance is not ICollection temp) @@ -123,28 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance[section.Key] = ParseInt(value, () => section.Path); - } - } - } - - public static void BindCore(IConfiguration configuration, ref IDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance[section.Key] = ParseInt(value, () => section.Path); - } - } - } - public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { if (instance is not IDictionary temp) @@ -184,7 +140,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section7) { IReadOnlyList? temp9 = instance.IReadOnlyList; - temp9 = temp9 is null ? new List() : new List(temp9); + temp9 = temp9 is null ? (IReadOnlyList)new List() : (IReadOnlyList)new List(temp9); BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); instance.IReadOnlyList = temp9; } @@ -192,7 +148,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section10) { IReadOnlyDictionary? temp12 = instance.IReadOnlyDictionary; - temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); + temp12 = temp12 is null ? (IReadOnlyDictionary)new Dictionary() : (IReadOnlyDictionary)temp12.ToDictionary(pair => pair.Key, pair => pair.Value); BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); instance.IReadOnlyDictionary = temp12; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index 5e7eeae29254a4..b6fb659d544d42 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -95,7 +95,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp2 = new List(); - BindCore(configuration, ref temp2, defaultValueIfNotFound: false, binderOptions); + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp2.Add(ParseInt(value, () => section.Path)); + } + } + int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp2.Count); temp2.CopyTo(instance, originalCount); @@ -116,42 +124,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["MyString"] is string value4) + if (configuration["MyString"] is string value3) { - instance.MyString = value4; + instance.MyString = value3; } - if (configuration["MyInt"] is string value5) + if (configuration["MyInt"] is string value4) { - instance.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { instance.MyInt = default; } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp8 = instance.MyList; - temp8 ??= new List(); - BindCore(section6, ref temp8, defaultValueIfNotFound: false, binderOptions); - instance.MyList = temp8; + List? temp7 = instance.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); + instance.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section9) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp11 = instance.MyArray; - temp11 ??= new int[0]; - BindCore(section9, ref temp11, defaultValueIfNotFound: false, binderOptions); - instance.MyArray = temp11; + int[]? temp10 = instance.MyArray; + temp10 ??= new int[0]; + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); + instance.MyArray = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section12) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp14 = instance.MyDictionary; - temp14 ??= new Dictionary(); - BindCore(section12, ref temp14, defaultValueIfNotFound: false, binderOptions); - instance.MyDictionary = temp14; + Dictionary? temp13 = instance.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); + instance.MyDictionary = temp13; } } @@ -159,9 +167,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value15) + if (configuration["MyInt"] is string value14) { - instance.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value14, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_PrimitivesOnly.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_PrimitivesOnly.generated.txt new file mode 100644 index 00000000000000..b703fb5f1c864b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_PrimitivesOnly.generated.txt @@ -0,0 +1,182 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 10, 16)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 12, 16)] + public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 11, 16)] + public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 13, 16)] + public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); + #endregion IConfiguration extensions. + + #region Core binding extensions. + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(int)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + if (section.Value is string value) + { + return ParseInt(value, () => section.Path); + } + } + else if (type == typeof(string)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + return section.Value; + } + else if (type == typeof(float)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + if (section.Value is string value) + { + return ParseFloat(value, () => section.Path); + } + } + else if (type == typeof(double)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + if (section.Value is string value) + { + return ParseDouble(value, () => section.Path); + } + } + + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + + public static float ParseFloat(string value, Func getPath) + { + try + { + return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(float)}'.", exception); + } + } + + public static double ParseDouble(string value, Func getPath) + { + try + { + return double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(double)}'.", exception); + } + } + #endregion Core binding extensions. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index 3fc5176bf50f09..c2e8f167bb4750 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -76,7 +76,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp1 = new List(); - BindCore(configuration, ref temp1, defaultValueIfNotFound: false, binderOptions); + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp1.Add(ParseInt(value, () => section.Path)); + } + } + int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp1.Count); temp1.CopyTo(instance, originalCount); @@ -97,42 +105,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["MyString"] is string value3) + if (configuration["MyString"] is string value2) { - instance.MyString = value3; + instance.MyString = value2; } - if (configuration["MyInt"] is string value4) + if (configuration["MyInt"] is string value3) { - instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value3, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { instance.MyInt = default; } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section4) { - List? temp7 = instance.MyList; - temp7 ??= new List(); - BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); - instance.MyList = temp7; + List? temp6 = instance.MyList; + temp6 ??= new List(); + BindCore(section4, ref temp6, defaultValueIfNotFound: false, binderOptions); + instance.MyList = temp6; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section7) { - int[]? temp10 = instance.MyArray; - temp10 ??= new int[0]; - BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); - instance.MyArray = temp10; + int[]? temp9 = instance.MyArray; + temp9 ??= new int[0]; + BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); + instance.MyArray = temp9; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section10) { - Dictionary? temp13 = instance.MyDictionary; - temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); - instance.MyDictionary = temp13; + Dictionary? temp12 = instance.MyDictionary; + temp12 ??= new Dictionary(); + BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); + instance.MyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index 81c23d7ceea65a..cd3f237917d4e3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -76,7 +76,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp1 = new List(); - BindCore(configuration, ref temp1, defaultValueIfNotFound: false, binderOptions); + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp1.Add(ParseInt(value, () => section.Path)); + } + } + int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp1.Count); temp1.CopyTo(instance, originalCount); @@ -97,42 +105,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["MyString"] is string value3) + if (configuration["MyString"] is string value2) { - instance.MyString = value3; + instance.MyString = value2; } - if (configuration["MyInt"] is string value4) + if (configuration["MyInt"] is string value3) { - instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value3, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { instance.MyInt = default; } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section4) { - List? temp7 = instance.MyList; - temp7 ??= new List(); - BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); - instance.MyList = temp7; + List? temp6 = instance.MyList; + temp6 ??= new List(); + BindCore(section4, ref temp6, defaultValueIfNotFound: false, binderOptions); + instance.MyList = temp6; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section7) { - int[]? temp10 = instance.MyArray; - temp10 ??= new int[0]; - BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); - instance.MyArray = temp10; + int[]? temp9 = instance.MyArray; + temp9 ??= new int[0]; + BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); + instance.MyArray = temp9; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section10) { - Dictionary? temp13 = instance.MyDictionary; - temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); - instance.MyDictionary = temp13; + Dictionary? temp12 = instance.MyDictionary; + temp12 ??= new Dictionary(); + BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); + instance.MyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs new file mode 100644 index 00000000000000..4373b404fc67f0 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.Extensions.Configuration.Binder.SourceGeneration; +using SourceGenerators.Tests; +using Xunit; + +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests +{ + [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] + public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase + { + internal sealed class ConfigBindingGenTestDriver + { + private readonly CSharpParseOptions _parseOptions; + private GeneratorDriver _generatorDriver; + private SourceGenerationSpec? _genSpec; + + private readonly LanguageVersion _langVersion; + private readonly IEnumerable? _assemblyReferences; + private Compilation _compilation = null; + + public ConfigBindingGenTestDriver( + LanguageVersion langVersion = LanguageVersion.LatestMajor, + IEnumerable? assemblyReferences = null) + { + _langVersion = langVersion; + + _assemblyReferences = assemblyReferences ?? s_compilationAssemblyRefs; + + _parseOptions = new CSharpParseOptions(langVersion).WithFeatures(new[] { + new KeyValuePair("InterceptorsPreview", "") , + new KeyValuePair("InterceptorsPreviewNamespaces", "Microsoft.Extensions.Configuration.Binder.SourceGeneration") + }); + + ConfigurationBindingGenerator generator = new() { OnSourceEmitting = spec => _genSpec = spec }; + _generatorDriver = CSharpGeneratorDriver.Create( + new ISourceGenerator[] { generator.AsSourceGenerator() }, + parseOptions: _parseOptions, + driverOptions: new GeneratorDriverOptions( + disabledOutputs: IncrementalGeneratorOutputKind.None, + trackIncrementalGeneratorSteps: true)); + } + + public async Task RunGeneratorAndUpdateCompilation(string? source = null) + { + await UpdateCompilationWithSource(source); + Assert.NotNull(_compilation); + + _generatorDriver = _generatorDriver.RunGeneratorsAndUpdateCompilation(_compilation, out Compilation outputCompilation, out _, CancellationToken.None); + GeneratorDriverRunResult runResult = _generatorDriver.GetRunResult(); + + return new ConfigBindingGenRunResult + { + OutputCompilation = outputCompilation, + Diagnostics = runResult.Diagnostics, + GeneratedSource = runResult.Results[0].GeneratedSources is { Length: not 0 } sources ? sources[0] : null, + TrackedSteps = runResult.Results[0].TrackedSteps[ConfigurationBindingGenerator.GenSpecTrackingName], + GenerationSpec = _genSpec + }; + } + + private async Task UpdateCompilationWithSource(string? source = null) + { + if (_compilation is not null && source is not null) + { + SyntaxTree newTree = CSharpSyntaxTree.ParseText(source, _parseOptions); + _compilation = _compilation.ReplaceSyntaxTree(_compilation.SyntaxTrees.First(), newTree); + } + else if (_compilation is null) + { + Assert.True(source is not null, "Generator test requires input source."); + using AdhocWorkspace workspace = RoslynTestUtils.CreateTestWorkspace(); + + Project project = RoslynTestUtils.CreateTestProject(workspace, _assemblyReferences, langVersion: _langVersion) + .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Annotations)) + .WithParseOptions(_parseOptions) + .WithDocuments(new string[] { source }); + Assert.True(project.Solution.Workspace.TryApplyChanges(project.Solution)); + + _compilation = (await project.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false))!; + } + } + } + } + + internal struct ConfigBindingGenRunResult + { + public required Compilation OutputCompilation { get; init; } + + public required GeneratedSourceResult? GeneratedSource { get; init; } + + /// + /// Diagnostics produced by the generator alone. Doesn't include any from other build participants. + /// + public required ImmutableArray Diagnostics { get; init; } + + public required ImmutableArray TrackedSteps { get; init; } + + public required SourceGenerationSpec? GenerationSpec { get; init; } + } + + internal enum ExpectedDiagnostics + { + None, + FromGeneratorOnly, + } + + internal static class ConfigBindingGenTestDriverExtensions + { + public static void ValidateIncrementalResult(this ConfigBindingGenRunResult result, + IncrementalStepRunReason inputReason, + IncrementalStepRunReason outputReason) + { + Assert.Collection(result.TrackedSteps, step => + { + Assert.Collection(step.Inputs, source => Assert.Equal(inputReason, source.Source.Outputs[source.OutputIndex].Reason)); + Assert.Collection(step.Outputs, output => Assert.Equal(outputReason, output.Reason)); + }); + } + + public static void ValidateDiagnostics(this ConfigBindingGenRunResult result, ExpectedDiagnostics expectedDiags) + { + ImmutableArray outputDiagnostics = result.OutputCompilation.GetDiagnostics(); + + if (expectedDiags is ExpectedDiagnostics.None) + { + foreach (Diagnostic diagnostic in outputDiagnostics) + { + Assert.True( + IsPermitted(diagnostic), + $"Generator caused dagnostic in output compilation: {diagnostic.GetMessage(CultureInfo.InvariantCulture)}."); + } + } + else + { + Debug.Assert(expectedDiags is ExpectedDiagnostics.FromGeneratorOnly); + + Assert.NotEmpty(result.Diagnostics); + Assert.False(outputDiagnostics.Any(diag => !IsPermitted(diag))); + } + + static bool IsPermitted(Diagnostic diagnostic) => diagnostic.Severity <= DiagnosticSeverity.Info; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 3c46f5f99818b1..e05a7737137128 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -141,7 +142,7 @@ public static void Main() public class MyClass { - public string MyString { get; set; } + public string? MyString { get; set; } public int MyInt { get; set; } public List MyList { get; set; } public Dictionary MyDictionary { get; set; } @@ -314,6 +315,30 @@ public class MyClass4 await VerifyAgainstBaselineUsingFile("Get.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } + [Fact] + public async Task Get_PrimitivesOnly() + { + string source = """ + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + config.Get(); + config.Get(typeof(string)); + config.Get(binderOptions => { }); + config.Get(typeof(double), binderOptions => { }); + } + } + """; + + await VerifyAgainstBaselineUsingFile("Get_PrimitivesOnly.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + [Fact] public async Task Get_T() { @@ -654,9 +679,9 @@ public class MyClass2 }" ; - var (d, r) = await RunGenerator(source); - Assert.Empty(r); - Assert.Empty(d); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + Assert.False(result.GeneratedSource.HasValue); + Assert.Empty(result.Diagnostics); } [Fact] @@ -736,6 +761,7 @@ public static void Main() section.Get(); } + // Diagnostic warning because we don't know how to instantiate two properties on this type. public class MyClassWithCustomCollections { public CustomDictionary CustomDictionary { get; set; } @@ -743,6 +769,7 @@ public class MyClassWithCustomCollections public ICustomDictionary ICustomDictionary { get; set; } public ICustomSet ICustomCollection { get; set; } public IReadOnlyList IReadOnlyList { get; set; } + // Diagnostic warning because we don't know how to instantiate the property type. public IReadOnlyDictionary UnsupportedIReadOnlyDictionaryUnsupported { get; set; } public IReadOnlyDictionary IReadOnlyDictionary { get; set; } } @@ -755,21 +782,26 @@ public class CustomList : List { } + // Diagnostic warning because we don't know how to instantiate this type. public interface ICustomDictionary : IDictionary { } + // Diagnostic warning because we don't know how to instantiate this type. public interface ICustomSet : ISet { } } """; - await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, validateOutputCompDiags: false, assessDiagnostics: (d) => - { - Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); - Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); - }); + ConfigBindingGenRunResult result = await VerifyAgainstBaselineUsingFile( + "Collections.generated.txt", + source, + expectedDiags: ExpectedDiagnostics.FromGeneratorOnly); + + ImmutableArray diagnostics = result.Diagnostics; + Assert.Equal(3, diagnostics.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); + Assert.Equal(3, diagnostics.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); } [Fact] @@ -811,14 +843,12 @@ public abstract class AbstractType_CannotInit } """; - await VerifyAgainstBaselineUsingFile( + ConfigBindingGenRunResult result = await VerifyAgainstBaselineUsingFile( "EmptyConfigType.generated.txt", source, - assessDiagnostics: (d) => - { - Assert.Equal(2, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); - }, - validateOutputCompDiags: false); + expectedDiags: ExpectedDiagnostics.FromGeneratorOnly); + + Assert.Equal(2, result.Diagnostics.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs index 7a47ad1cb27251..cbbd34e7fc41da 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -9,10 +9,10 @@ using System.IO; using System.Linq; using System.Reflection; -using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Binder.SourceGeneration; using Microsoft.Extensions.DependencyInjection; @@ -24,6 +24,9 @@ namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests { public partial class ConfigurationBindingGeneratorTests { + /// + /// Keep in sync with variants, e.g. . + /// private const string BindCallSampleCode = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -63,6 +66,7 @@ private static class Diagnostics } private static readonly Assembly[] s_compilationAssemblyRefs = new[] { + typeof(BitArray).Assembly, typeof(ConfigurationBinder).Assembly, typeof(ConfigurationBuilder).Assembly, typeof(CultureInfo).Assembly, @@ -87,18 +91,19 @@ private enum ExtensionClassType private static async Task VerifyThatSourceIsGenerated(string testSourceCode) { - var (d, r) = await RunGenerator(testSourceCode); - Assert.Equal(1, r.Length); - Assert.Empty(d); - Assert.True(r[0].SourceText.Lines.Count > 10); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(testSourceCode); + GeneratedSourceResult? source = result.GeneratedSource; + + Assert.NotNull(source); + Assert.Empty(result.Diagnostics); + Assert.True(source.Value.SourceText.Lines.Count > 10); } - private static async Task VerifyAgainstBaselineUsingFile( + private static async Task VerifyAgainstBaselineUsingFile( string filename, string testSourceCode, - Action>? assessDiagnostics = null, ExtensionClassType extType = ExtensionClassType.None, - bool validateOutputCompDiags = true) + ExpectedDiagnostics expectedDiags = ExpectedDiagnostics.None) { string path = extType is ExtensionClassType.None ? Path.Combine("Baselines", filename) @@ -107,70 +112,52 @@ private static async Task VerifyAgainstBaselineUsingFile( string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) .Split(Environment.NewLine); - var (d, r) = await RunGenerator(testSourceCode, validateOutputCompDiags); - bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(testSourceCode); + result.ValidateDiagnostics(expectedDiags); + + SourceText resultSourceText = result.GeneratedSource.Value.SourceText; + bool resultEqualsBaseline = RoslynTestUtils.CompareLines(expectedLines, resultSourceText, out string errorMessage); #if UPDATE_BASELINES - if (!success) + if (!resultEqualsBaseline) { - string? repoRootDir = Environment.GetEnvironmentVariable("RepoRootDir"); - Assert.True(repoRootDir is not null, "To update baselines, specifiy the root runtime repo dir"); + const string envVarName = "RepoRootDir"; + string errMessage = $"To update baselines, specify a '{envVarName}' environment variable. See this assembly's README.md doc for more details."; + + string? repoRootDir = Environment.GetEnvironmentVariable(envVarName); + Assert.True(repoRootDir is not null, errMessage); - IEnumerable lines = r[0].SourceText.Lines.Select(l => l.ToString()); + IEnumerable lines = resultSourceText.Lines.Select(l => l.ToString()); string source = string.Join(Environment.NewLine, lines).TrimEnd(Environment.NewLine.ToCharArray()) + Environment.NewLine; path = Path.Combine($"{repoRootDir}\\src\\libraries\\Microsoft.Extensions.Configuration.Binder\\tests\\SourceGenerationTests\\", path); await File.WriteAllTextAsync(path, source).ConfigureAwait(false); - success = true; + resultEqualsBaseline = true; } #endif - Assert.Single(r); - (assessDiagnostics ?? ((d) => Assert.Empty(d))).Invoke(d); - Assert.True(success, errorMessage); + Assert.True(resultEqualsBaseline, errorMessage); + + return result; } - private static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( - string testSourceCode, - bool validateOutputCompDiags = false, + private static async Task RunGeneratorAndUpdateCompilation( + string source, LanguageVersion langVersion = LanguageVersion.CSharp12, - IEnumerable? references = null) + IEnumerable? assemblyReferences = null) { - using var workspace = RoslynTestUtils.CreateTestWorkspace(); - CSharpParseOptions parseOptions = new CSharpParseOptions(langVersion).WithFeatures(new[] { - new KeyValuePair("InterceptorsPreview", ""), - new KeyValuePair("InterceptorsPreviewNamespaces", "Microsoft.Extensions.Configuration.Binder.SourceGeneration") - }); - - Project proj = RoslynTestUtils.CreateTestProject(workspace, references ?? s_compilationAssemblyRefs, langVersion: langVersion) - .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Annotations)) - .WithDocuments(new string[] { testSourceCode }) - .WithParseOptions(parseOptions); - - Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution)); - - Compilation comp = await proj.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false); - CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { new ConfigurationBindingGenerator().AsSourceGenerator() }, parseOptions: parseOptions); - GeneratorDriver gd = cgd.RunGeneratorsAndUpdateCompilation(comp, out Compilation outputCompilation, out _, CancellationToken.None); - GeneratorDriverRunResult runResult = gd.GetRunResult(); - - if (validateOutputCompDiags) - { - ImmutableArray diagnostics = outputCompilation.GetDiagnostics(); - Assert.False(diagnostics.Any(d => d.Severity > DiagnosticSeverity.Info)); - } - - return (runResult.Results[0].Diagnostics, runResult.Results[0].GeneratedSources); + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(langVersion, assemblyReferences); + return await driver.RunGeneratorAndUpdateCompilation(source); } - public static List GetAssemblyRefsWithAdditional(params Type[] additional) + private static List GetAssemblyRefsWithAdditional(params Type[] additional) { List assemblies = new(s_compilationAssemblyRefs); assemblies.AddRange(additional.Select(t => t.Assembly)); return assemblies; } - public static HashSet GetFilteredAssemblyRefs(IEnumerable exclusions) + private static HashSet GetFilteredAssemblyRefs(IEnumerable exclusions) { HashSet assemblies = new(s_compilationAssemblyRefs); foreach (Type exclusion in exclusions) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs new file mode 100644 index 00000000000000..aff9a0c20364ca --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Incremental.cs @@ -0,0 +1,362 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.Extensions.Configuration.Binder.SourceGeneration; +using SourceGenerators.Tests; +using Xunit; + +namespace Microsoft.Extensions.SourceGeneration.Configuration.Binder.Tests +{ + public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTestsBase + { + [ActiveIssue("https://github.com/dotnet/runtime/issues/52062", TestPlatforms.Browser)] + public sealed class IncrementalTests + { + [Fact] + public async Task CompilingTheSameSourceResultsInEqualModels() + { + SourceGenerationSpec spec1 = (await new ConfigBindingGenTestDriver().RunGeneratorAndUpdateCompilation(BindCallSampleCode)).GenerationSpec; + SourceGenerationSpec spec2 = (await new ConfigBindingGenTestDriver().RunGeneratorAndUpdateCompilation(BindCallSampleCode)).GenerationSpec; + + Assert.NotSame(spec1, spec2); + GeneratorTestHelpers.AssertStructurallyEqual(spec1, spec2); + + Assert.Equal(spec1, spec2); + Assert.Equal(spec1.GetHashCode(), spec2.GetHashCode()); + } + + [Fact] + public async Task RunWithNoDiags_Then_NoEdit() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCode); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + result = await driver.RunGeneratorAndUpdateCompilation(); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Unchanged); + } + + [Fact] + public async Task RunWithNoDiags_Then_ChangeInputOrder() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCode); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + // We expect different spec because diag locations are different. + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_ReorderedInvocations); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + + // We expect different spec because members are reordered. + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_ReorderedConfigTypeMembers); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + } + + [Fact] + public async Task RunWithNoDiags_Then_EditWithNoDiags() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCode); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithDifferentConfigTypeName); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + } + + [Fact] + public async Task RunWithNoDiags_Then_EditWithDiags() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCode); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + } + + [Fact] + public async Task RunWithDiags_Then_NoEdit() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + result = await driver.RunGeneratorAndUpdateCompilation(); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Unchanged); + } + + [Fact] + public async Task RunWithDiags_Then_ChangeInputOrder() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + // We expect different spec because diag locations are different. + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember_ReorderedInvocations); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + + // We expect different spec because members are reordered. + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember_ReorderedConfigTypeMembers); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + } + + [Fact] + public async Task RunWithDiags_Then_EditWithNoDiags() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCode); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + } + + [Fact] + public async Task RunWithDiags_Then_EditWithDiags() + { + ConfigBindingGenTestDriver driver = new ConfigBindingGenTestDriver(); + + ConfigBindingGenRunResult result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember); + result.ValidateIncrementalResult(IncrementalStepRunReason.New, IncrementalStepRunReason.New); + + result = await driver.RunGeneratorAndUpdateCompilation(BindCallSampleCodeVariant_WithUnsupportedMember_WithDiffMemberName); + result.ValidateIncrementalResult(IncrementalStepRunReason.Modified, IncrementalStepRunReason.Modified); + } + } + + #region Incremental test sources. + /// + /// Keep in sync with . + /// + private const string BindCallSampleCodeVariant_ReorderedInvocations = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + config.Bind(configObj); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + } + + public class MyClass2 { } + } + """; + + /// + /// Keep in sync with . + /// + private const string BindCallSampleCodeVariant_ReorderedConfigTypeMembers = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + config.Bind(configObj); + } + + public class MyClass + { + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public string MyString { get; set; } + public int MyInt { get; set; } + public Dictionary MyComplexDictionary { get; set; } + } + + public class MyClass2 { } + } + """; + + /// + /// Keep in sync with . + /// + private const string BindCallSampleCodeVariant_WithDifferentConfigTypeName = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass0 configObj = new(); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + config.Bind(configObj); + } + + public class MyClass0 + { + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public string MyString { get; set; } + public int MyInt { get; set; } + public Dictionary MyComplexDictionary { get; set; } + } + + public class MyClass2 { } + } + """; + + private const string BindCallSampleCodeVariant_WithUnsupportedMember = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind(configObj); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + public int[,] UnsupportedMember { get; set; } + } + + public class MyClass2 { } + } + """; + + private const string BindCallSampleCodeVariant_WithUnsupportedMember_ReorderedInvocations = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind("key", configObj); + config.Bind(configObj); + config.Bind(configObj, options => { }); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + public int[,] UnsupportedMember { get; set; } + } + + public class MyClass2 { } + } + """; + + private const string BindCallSampleCodeVariant_WithUnsupportedMember_ReorderedConfigTypeMembers = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind("key", configObj); + config.Bind(configObj); + config.Bind(configObj, options => { }); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public int[,] UnsupportedMember { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + public List MyList { get; set; } + } + + public class MyClass2 { } + } + """; + + private const string BindCallSampleCodeVariant_WithUnsupportedMember_WithDiffMemberName = """ + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass configObj = new(); + config.Bind(configObj); + config.Bind(configObj, options => { }); + config.Bind("key", configObj); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + public Dictionary MyDictionary { get; set; } + public Dictionary MyComplexDictionary { get; set; } + public int[,] UnsupportedMember_DiffMemberName { get; set; } + } + + public class MyClass2 { } + } + """; + #endregion Incremental test sources. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 846e64d904d531..d93607d3763996 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -27,10 +27,10 @@ public partial class ConfigurationBindingGeneratorTests : ConfigurationBinderTes [InlineData(LanguageVersion.CSharp10)] public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion) { - var (d, r) = await RunGenerator(BindCallSampleCode, langVersion: langVersion); - Assert.Empty(r); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(BindCallSampleCode, langVersion: langVersion); + Assert.False(result.GeneratedSource.HasValue); - Diagnostic diagnostic = Assert.Single(d); + Diagnostic diagnostic = Assert.Single(result.Diagnostics); Assert.True(diagnostic.Id == "SYSLIB1102"); Assert.Contains("C# 12", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity); @@ -75,11 +75,11 @@ public record struct MyRecordStruct { } } """; - var (d, r) = await RunGenerator(source); - Assert.Empty(r); - Assert.Equal(7, d.Count()); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + Assert.False(result.GeneratedSource.HasValue); + Assert.Equal(7, result.Diagnostics.Count()); - foreach (Diagnostic diagnostic in d) + foreach (Diagnostic diagnostic in result.Diagnostics) { Assert.True(diagnostic.Id == Diagnostics.ValueTypesInvalidForBind.Id); Assert.Contains(Diagnostics.ValueTypesInvalidForBind.Title, diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); @@ -111,11 +111,11 @@ public record struct MyRecordStruct { } } """; - var (d, r) = await RunGenerator(source); - Assert.Empty(r); - Assert.Equal(2, d.Count()); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + Assert.False(result.GeneratedSource.HasValue); + Assert.Equal(2, result.Diagnostics.Count()); - foreach (Diagnostic diagnostic in d) + foreach (Diagnostic diagnostic in result.Diagnostics) { Assert.True(diagnostic.Id == Diagnostics.CouldNotDetermineTypeInfo.Id); Assert.Contains(Diagnostics.CouldNotDetermineTypeInfo.Title, diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); @@ -163,11 +163,11 @@ public class MyClass { } } """; - var (d, r) = await RunGenerator(source); - Assert.Empty(r); - Assert.Equal(6, d.Count()); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source); + Assert.False(result.GeneratedSource.HasValue); + Assert.Equal(6, result.Diagnostics.Count()); - foreach (Diagnostic diagnostic in d) + foreach (Diagnostic diagnostic in result.Diagnostics) { Assert.True(diagnostic.Id == Diagnostics.CouldNotDetermineTypeInfo.Id); Assert.Contains(Diagnostics.CouldNotDetermineTypeInfo.Title, diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture)); @@ -218,22 +218,15 @@ public class MyClass0 { } async Task Test(bool expectOutput) { - var (d, r) = await RunGenerator(source, references: GetFilteredAssemblyRefs(exclusions)); - - Assert.Empty(d); - - if (expectOutput) - { - Assert.Single(r); - } - else - { - Assert.Empty(r); - } + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source, assemblyReferences: GetFilteredAssemblyRefs(exclusions)); + Assert.Empty(result.Diagnostics); + Action ValidateSourceResult = expectOutput ? () => Assert.NotNull(result.GeneratedSource) : () => Assert.False(result.GeneratedSource.HasValue); + ValidateSourceResult(); } } [Fact] + [ActiveIssue("Work out why we aren't getting all the expected diagnostics.")] public async Task IssueDiagnosticsForAllOffendingCallsites() { string source = """ @@ -282,10 +275,10 @@ public class AnotherGraphWithUnsupportedMembers } """; - var (d, r) = await RunGenerator(source, references: GetAssemblyRefsWithAdditional(typeof(ImmutableArray<>), typeof(Encoding), typeof(JsonSerializer))); - Assert.Single(r); - Assert.Equal(47, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); - Assert.Equal(44, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source, assemblyReferences: GetAssemblyRefsWithAdditional(typeof(ImmutableArray<>), typeof(Encoding), typeof(JsonSerializer))); + Assert.NotNull(result.GeneratedSource); + Assert.True(result.Diagnostics.Any(diag => diag.Id == Diagnostics.TypeNotSupported.Id)); + Assert.True(result.Diagnostics.Any(diag => diag.Id == Diagnostics.PropertyNotSupported.Id)); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index fc8db157eddeea..848d93b32a475a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -2,8 +2,10 @@ $(NetCoreAppCurrent);$(NetFrameworkMinimum) true - - SYSLIB1100,SYSLIB1101 + + $(NoWarn);SYSLIB1100,SYSLIB1101 + + $(NoWarn);SYSLIB1103,SYSLIB1104 $(Features);InterceptorsPreview $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -22,6 +24,7 @@ + @@ -46,17 +49,16 @@ - + PreserveNewest + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 1f12dab5b9ac44..e83340eb0eae55 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -11,7 +11,8 @@ $(InterceptorsPreviewNamespaces);Microsoft.Extensions.Configuration.Binder.SourceGeneration true - true + + $(NoWarn);SYSLIB1100;SYSLIB1101 Console logger provider implementation for Microsoft.Extensions.Logging. diff --git a/src/libraries/System.Text.Json/gen/Helpers/DiagnosticInfo.cs b/src/libraries/System.Text.Json/gen/Helpers/DiagnosticInfo.cs deleted file mode 100644 index 493f79191d4375..00000000000000 --- a/src/libraries/System.Text.Json/gen/Helpers/DiagnosticInfo.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Linq; -using System.Numerics.Hashing; -using Microsoft.CodeAnalysis; - -namespace System.Text.Json.SourceGeneration -{ - /// - /// Descriptor for diagnostic instances using structural equality comparison. - /// Provides a work-around for https://github.com/dotnet/roslyn/issues/68291. - /// - public readonly struct DiagnosticInfo : IEquatable - { - public required DiagnosticDescriptor Descriptor { get; init; } - public required object?[] MessageArgs { get; init; } - public required Location? Location { get; init; } - - public Diagnostic CreateDiagnostic() - => Diagnostic.Create(Descriptor, Location, MessageArgs); - - public override readonly bool Equals(object? obj) => obj is DiagnosticInfo info && Equals(info); - public readonly bool Equals(DiagnosticInfo other) - { - return Descriptor.Equals(other.Descriptor) && - MessageArgs.SequenceEqual(other.MessageArgs) && - Location == other.Location; - } - - public override readonly int GetHashCode() - { - int hashCode = Descriptor.GetHashCode(); - foreach (object? messageArg in MessageArgs) - { - hashCode = HashHelpers.Combine(hashCode, messageArg?.GetHashCode() ?? 0); - } - - hashCode = HashHelpers.Combine(hashCode, Location?.GetHashCode() ?? 0); - return hashCode; - } - } -} diff --git a/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs index 7d280ce7603c2d..3f3ecb506fd83d 100644 --- a/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs @@ -25,8 +25,6 @@ internal static class RoslynExtensions return compilation.GetBestTypeByMetadataName(type.FullName); } - public static string GetFullyQualifiedName(this ITypeSymbol type) => type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); - public static Location? GetLocation(this ISymbol typeSymbol) => typeSymbol.Locations.Length > 0 ? typeSymbol.Locations[0] : null; @@ -36,12 +34,6 @@ internal static class RoslynExtensions return reference?.SyntaxTree.GetLocation(reference.Span); } - /// - /// Creates a copy of the Location instance that does not capture a reference to Compilation. - /// - public static Location GetTrimmedLocation(this Location location) - => Location.Create(location.SourceTree?.FilePath ?? "", location.SourceSpan, location.GetLineSpan().Span); - /// /// Returns true if the specified location is contained in one of the syntax trees in the compilation. /// diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 0f3b11b038bc93..e0dac6a9ad82ce 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -60,12 +60,7 @@ public void ReportDiagnostic(DiagnosticDescriptor descriptor, Location? location location = _contextClassLocation; } - Diagnostics.Add(new DiagnosticInfo - { - Descriptor = descriptor, - Location = location.GetTrimmedLocation(), - MessageArgs = messageArgs ?? Array.Empty(), - }); + Diagnostics.Add(DiagnosticInfo.Create(descriptor, location, messageArgs)); } public Parser(KnownTypeSymbols knownSymbols) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs index 4c58a3d968ac54..7520f9bc75a6f5 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn3.11.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; +using SourceGenerators; namespace System.Text.Json.SourceGeneration { diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs index e3f8b4aacf6c5b..447f54c7f07821 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Roslyn4.0.cs @@ -9,6 +9,7 @@ #if !ROSLYN4_4_OR_GREATER using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; #endif +using SourceGenerators; namespace System.Text.Json.SourceGeneration { diff --git a/src/libraries/System.Text.Json/gen/Model/ContextGenerationSpec.cs b/src/libraries/System.Text.Json/gen/Model/ContextGenerationSpec.cs index 1e2ee2d737e009..00c7192c3ae58c 100644 --- a/src/libraries/System.Text.Json/gen/Model/ContextGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/ContextGenerationSpec.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; -using System.Text.Json.Serialization; +using SourceGenerators; namespace System.Text.Json.SourceGeneration { diff --git a/src/libraries/System.Text.Json/gen/Model/ParameterGenerationSpec.cs b/src/libraries/System.Text.Json/gen/Model/ParameterGenerationSpec.cs index 2945b20b730b15..68e32d01531569 100644 --- a/src/libraries/System.Text.Json/gen/Model/ParameterGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/ParameterGenerationSpec.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using SourceGenerators; + namespace System.Text.Json.SourceGeneration { /// diff --git a/src/libraries/System.Text.Json/gen/Model/PropertyGenerationSpec.cs b/src/libraries/System.Text.Json/gen/Model/PropertyGenerationSpec.cs index 56b42970f68893..214c32b4d19e21 100644 --- a/src/libraries/System.Text.Json/gen/Model/PropertyGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/PropertyGenerationSpec.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Text.Json.Serialization; +using SourceGenerators; namespace System.Text.Json.SourceGeneration { diff --git a/src/libraries/System.Text.Json/gen/Model/PropertyInitializerGenerationSpec.cs b/src/libraries/System.Text.Json/gen/Model/PropertyInitializerGenerationSpec.cs index 9fc68a11928470..608ce8e887d725 100644 --- a/src/libraries/System.Text.Json/gen/Model/PropertyInitializerGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/PropertyInitializerGenerationSpec.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using SourceGenerators; + namespace System.Text.Json.SourceGeneration { /// diff --git a/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs b/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs index 7e94f824bae8cb..83b587fb962f7e 100644 --- a/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/SourceGenerationOptionsSpec.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json.Serialization; +using SourceGenerators; namespace System.Text.Json.SourceGeneration { diff --git a/src/libraries/System.Text.Json/gen/Model/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/Model/TypeGenerationSpec.cs index 189295bcb971ca..9b71bf16438b89 100644 --- a/src/libraries/System.Text.Json/gen/Model/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/Model/TypeGenerationSpec.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Text.Json.Serialization; using Microsoft.CodeAnalysis; +using SourceGenerators; namespace System.Text.Json.SourceGeneration { diff --git a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets index 4020a05cb421db..23add6278d7c07 100644 --- a/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets +++ b/src/libraries/System.Text.Json/gen/System.Text.Json.SourceGeneration.targets @@ -30,8 +30,11 @@ + + + @@ -54,9 +57,7 @@ - - @@ -74,6 +75,5 @@ - diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs index 7a38a7e5fb5128..daa6498cbc9b2d 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis; +using SourceGenerators.Tests; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -29,7 +30,7 @@ public static void CompilingTheSameSourceResultsInEqualModels(Func ContextGenerationSpec ctx2 = result2.ContextGenerationSpecs[i]; Assert.NotSame(ctx1, ctx2); - AssertStructurallyEqual(ctx1, ctx2); + GeneratorTestHelpers.AssertStructurallyEqual(ctx1, ctx2); Assert.Equal(ctx1, ctx2); Assert.Equal(ctx1.GetHashCode(), ctx2.GetHashCode()); @@ -86,7 +87,7 @@ public partial class JsonContext : JsonSerializerContext { } ContextGenerationSpec ctx2 = result2.ContextGenerationSpecs[0]; Assert.NotSame(ctx1, ctx2); - AssertStructurallyEqual(ctx1, ctx2); + GeneratorTestHelpers.AssertStructurallyEqual(ctx1, ctx2); Assert.Equal(ctx1, ctx2); Assert.Equal(ctx1.GetHashCode(), ctx2.GetHashCode()); @@ -377,74 +378,5 @@ public static IEnumerable GetCompilationHelperFactories() .Where(m => m.ReturnType == typeof(Compilation) && m.GetParameters().Length == 0) .Select(m => new object[] { Delegate.CreateDelegate(typeof(Func), m) }); } - - /// - /// Asserts for structural equality, returning a path to the mismatching data when not equal. - /// - private static void AssertStructurallyEqual(T expected, T actual) - { - CheckAreEqualCore(expected, actual, new()); - static void CheckAreEqualCore(object expected, object actual, Stack path) - { - if (expected is null || actual is null) - { - if (expected is not null || actual is not null) - { - FailNotEqual(); - } - - return; - } - - Type type = expected.GetType(); - if (type != actual.GetType()) - { - FailNotEqual(); - return; - } - - if (expected is IEnumerable leftCollection) - { - if (actual is not IEnumerable rightCollection) - { - FailNotEqual(); - return; - } - - object?[] expectedValues = leftCollection.Cast().ToArray(); - object?[] actualValues = rightCollection.Cast().ToArray(); - - for (int i = 0; i < Math.Max(expectedValues.Length, actualValues.Length); i++) - { - object? expectedElement = i < expectedValues.Length ? expectedValues[i] : ""; - object? actualElement = i < actualValues.Length ? actualValues[i] : ""; - - path.Push($"[{i}]"); - CheckAreEqualCore(expectedElement, actualElement, path); - path.Pop(); - } - } - - if (type.GetProperty("EqualityContract", BindingFlags.Instance | BindingFlags.NonPublic, null, returnType: typeof(Type), types: Array.Empty(), null) != null) - { - // Type is a C# record, run pointwise equality comparison. - foreach (PropertyInfo property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - path.Push("." + property.Name); - CheckAreEqualCore(property.GetValue(expected), property.GetValue(actual), path); - path.Pop(); - } - - return; - } - - if (!expected.Equals(actual)) - { - FailNotEqual(); - } - - void FailNotEqual() => Assert.Fail($"Value not equal in ${string.Join("", path.Reverse())}: expected {expected}, but was {actual}."); - } - } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets index a700b2a9f3a385..56bf105dc1fddf 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.targets @@ -12,6 +12,7 @@ + From 2e50c1e87261c61d082b36d0ef6145eb1b652adf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:28:26 -0700 Subject: [PATCH 340/345] [release/8.0] [wasm] Endian fix for Webcil (#92495) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [wasm] Endian fix for Webcil 'dotnet new blazorwasm' command failed on s390x and was throwing a not implemented exception The issue was with with the WebCil writer and reader, specific endianness conversions relating to the webcil payload were not implemented for big endian machines. We considered fixing the generic implementation, but there were only two structures in use: WebcilHeader and WebcilSectionHeader, so it was easier to handle them explicitly. * Fix infinite recursion * rename var --------- Co-authored-by: Sanjam Panda Co-authored-by: Aleksey Kliger (λgeek) --- .../Microsoft.NET.WebAssembly.Webcil.csproj | 1 + .../WebcilConverter.cs | 34 +++++++++++------ .../WebcilReader.cs | 37 +++++++++++++++---- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/tasks/Microsoft.NET.WebAssembly.Webcil/Microsoft.NET.WebAssembly.Webcil.csproj b/src/tasks/Microsoft.NET.WebAssembly.Webcil/Microsoft.NET.WebAssembly.Webcil.csproj index c35eb57e80686b..d09ae4a569a598 100644 --- a/src/tasks/Microsoft.NET.WebAssembly.Webcil/Microsoft.NET.WebAssembly.Webcil.csproj +++ b/src/tasks/Microsoft.NET.WebAssembly.Webcil/Microsoft.NET.WebAssembly.Webcil.csproj @@ -16,6 +16,7 @@ + diff --git a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs index a38af7270a2dad..13c34bde4b8ea1 100644 --- a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs +++ b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Buffers.Binary; using System.IO; using System.Collections.Immutable; using System.Reflection.PortableExecutable; @@ -174,16 +175,23 @@ public unsafe void GatherInfo(PEReader peReader, out WCFileInfo wcInfo, out PEFi SectionStart: firstWCSection); } - private static void WriteHeader(Stream s, WebcilHeader header) + private static void WriteHeader(Stream s, WebcilHeader webcilHeader) { - WriteStructure(s, header); + if (!BitConverter.IsLittleEndian) + { + webcilHeader.version_major = BinaryPrimitives.ReverseEndianness(webcilHeader.version_major); + webcilHeader.version_minor = BinaryPrimitives.ReverseEndianness(webcilHeader.version_minor); + webcilHeader.coff_sections = BinaryPrimitives.ReverseEndianness(webcilHeader.coff_sections); + webcilHeader.pe_cli_header_rva = BinaryPrimitives.ReverseEndianness(webcilHeader.pe_cli_header_rva); + webcilHeader.pe_cli_header_size = BinaryPrimitives.ReverseEndianness(webcilHeader.pe_cli_header_size); + webcilHeader.pe_debug_rva = BinaryPrimitives.ReverseEndianness(webcilHeader.pe_debug_rva); + webcilHeader.pe_debug_size = BinaryPrimitives.ReverseEndianness(webcilHeader.pe_debug_size); + } + WriteStructure(s, webcilHeader); } private static void WriteSectionHeaders(Stream s, ImmutableArray sectionsHeaders) { - // FIXME: fixup endianness - if (!BitConverter.IsLittleEndian) - throw new NotImplementedException(); foreach (var sectionHeader in sectionsHeaders) { WriteSectionHeader(s, sectionHeader); @@ -192,6 +200,16 @@ private static void WriteSectionHeaders(Stream s, ImmutableArray(Stream s, T structure) where T : unmanaged { - // FIXME: fixup endianness - if (!BitConverter.IsLittleEndian) - throw new NotImplementedException(); unsafe { byte* p = (byte*)&structure; @@ -212,9 +227,6 @@ private static void WriteStructure(Stream s, T structure) private static void WriteStructure(Stream s, T structure) where T : unmanaged { - // FIXME: fixup endianness - if (!BitConverter.IsLittleEndian) - throw new NotImplementedException(); int size = Marshal.SizeOf(); byte[] buffer = new byte[size]; IntPtr ptr = IntPtr.Zero; diff --git a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilReader.cs b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilReader.cs index 4f42f827986643..ac4f9d86095a90 100644 --- a/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilReader.cs +++ b/src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilReader.cs @@ -6,7 +6,7 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; - +using System.Buffers.Binary; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; @@ -63,14 +63,20 @@ private unsafe bool ReadHeader() { return false; } - if (!BitConverter.IsLittleEndian) - { - throw new NotImplementedException("TODO: implement big endian support"); - } fixed (byte* p = buffer) { header = *(WebcilHeader*)p; } + if (!BitConverter.IsLittleEndian) + { + header.version_major = BinaryPrimitives.ReverseEndianness(header.version_major); + header.version_minor = BinaryPrimitives.ReverseEndianness(header.version_minor); + header.coff_sections = BinaryPrimitives.ReverseEndianness(header.coff_sections); + header.pe_cli_header_rva = BinaryPrimitives.ReverseEndianness(header.pe_cli_header_rva); + header.pe_cli_header_size = BinaryPrimitives.ReverseEndianness(header.pe_cli_header_size); + header.pe_debug_rva = BinaryPrimitives.ReverseEndianness(header.pe_debug_rva); + header.pe_debug_rva = BinaryPrimitives.ReverseEndianness(header.pe_debug_size); + } if (header.id[0] != 'W' || header.id[1] != 'b' || header.id[2] != 'I' || header.id[3] != 'L' || header.version_major != Internal.Constants.WC_VERSION_MAJOR @@ -346,6 +352,7 @@ private long TranslateRVA(uint rva) private unsafe ImmutableArray ReadSections() { + WebcilSectionHeader secheader; var sections = ImmutableArray.CreateBuilder(_header.coff_sections); var buffer = new byte[Marshal.SizeOf()]; _stream.Seek(SectionDirectoryOffset + _webcilInWasmOffset, SeekOrigin.Begin); @@ -357,8 +364,24 @@ private unsafe ImmutableArray ReadSections() } fixed (byte* p = buffer) { - // FIXME endianness - sections.Add(*(WebcilSectionHeader*)p); + secheader = (*(WebcilSectionHeader*)p); + } + if (!BitConverter.IsLittleEndian) + { + sections.Add + ( + new WebcilSectionHeader + ( + virtualSize: BinaryPrimitives.ReverseEndianness(secheader.VirtualSize), + virtualAddress: BinaryPrimitives.ReverseEndianness(secheader.VirtualAddress), + sizeOfRawData: BinaryPrimitives.ReverseEndianness(secheader.SizeOfRawData), + pointerToRawData: BinaryPrimitives.ReverseEndianness(secheader.PointerToRawData) + ) + ); + } + else + { + sections.Add(secheader); } } return sections.MoveToImmutable(); From dedfe8e49ac0d0a2a817da5be0f84357acbe6454 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:30:29 -0700 Subject: [PATCH 341/345] Update dependencies from https://github.com/dotnet/source-build-externals build 20231002.1 (#92935) Microsoft.SourceBuild.Intermediate.source-build-externals From Version 8.0.0-alpha.1.23475.1 -> To Version 8.0.0-alpha.1.23502.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1f220ede26d087..12cfc3ce525f94 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -100,9 +100,9 @@ 7b55da982fc6e71c1776c4de89111aee0eecb45a - + https://github.com/dotnet/source-build-externals - e04156dbe14f882a80d4499dbebd45ab156b6c3c + ed17956dbc31097b7ba6a66be086f4a70a97d84f From a7c94198273b091f02b89e98073e24ae3a0c5b58 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:30:41 -0700 Subject: [PATCH 342/345] [release/8.0] Update dependencies from dotnet/cecil dotnet/hotreload-utils (#92932) * Update dependencies from https://github.com/dotnet/cecil build 20231002.1 Microsoft.DotNet.Cecil From Version 0.11.4-alpha.23476.1 -> To Version 0.11.4-alpha.23502.1 * Update dependencies from https://github.com/dotnet/hotreload-utils build 20231002.1 Microsoft.DotNet.HotReload.Utils.Generator.BuildTool From Version 8.0.0-alpha.0.23475.1 -> To Version 8.0.0-alpha.0.23502.1 --------- Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 12cfc3ce525f94..9c18388aa5346d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -85,9 +85,9 @@ 02fe27cd6a9b001c8feb7938e6ef4b3799745759b - + https://github.com/dotnet/cecil - 13d6536e2dc92404da76d61d248badc040eb0de0 + 64a8874f3c485657e732ca56a5f24e2095740103 @@ -350,9 +350,9 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization 492f7464d31d9599531fab2a67bc2422046f5133 - + https://github.com/dotnet/hotreload-utils - 6c20c1d568568b9b2da84f878ac9cb4a48aaa4e5 + 94979ba9c2904e39ddb9aa255a288caacd6ce166 https://github.com/dotnet/runtime-assets diff --git a/eng/Versions.props b/eng/Versions.props index 1663485ec06805..ef9555ba255cbe 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -186,7 +186,7 @@ 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 8.0.0-prerelease.23407.2 - 8.0.0-alpha.0.23475.1 + 8.0.0-alpha.0.23502.1 2.4.2 1.0.0 2.4.5 @@ -213,7 +213,7 @@ 8.0.0-rc.1.23406.6 - 0.11.4-alpha.23476.1 + 0.11.4-alpha.23502.1 8.0.0-rc.1.23406.6 From 0eeb6b268afa56fc173264b9905e8287a681db64 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Tue, 3 Oct 2023 15:42:56 -0400 Subject: [PATCH 343/345] [release/8.0][wasm] Use intended ports when running `DevServer` (#92906) * [wasm] Ignore empty `$ASPNETCORE_URLS` * [wasm] DevServer: honor urls specified in the options * [wasm] CI: Don't trigger non-wbt jobs on wasm-app-host changes * CI: don't trigger wasm runtime tests on wasm-app-host changes * [wasm] wasmbrowser - change the default webserver port to 0, to randomly select a port --- eng/pipelines/common/evaluate-default-paths.yml | 2 ++ src/mono/wasm/host/BrowserHost.cs | 2 +- src/mono/wasm/host/DevServer/DevServer.cs | 3 ++- src/mono/wasm/host/RuntimeConfigJson.cs | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/eng/pipelines/common/evaluate-default-paths.yml b/eng/pipelines/common/evaluate-default-paths.yml index 5fb74a3741f413..0e4279a9697b94 100644 --- a/eng/pipelines/common/evaluate-default-paths.yml +++ b/eng/pipelines/common/evaluate-default-paths.yml @@ -241,6 +241,7 @@ jobs: - src/mono/tools/* - src/mono/wasi/* - src/mono/wasm/debugger/* + - src/mono/wasm/host/* - src/mono/wasm/Wasm.Build.Tests/* - ${{ parameters._const_paths._wasm_pipelines }} - ${{ parameters._const_paths._always_exclude }} @@ -258,6 +259,7 @@ jobs: - eng/testing/workloads-testing.targets - src/mono/mono/component/mini-wasm-debugger.c - src/mono/wasm/debugger/* + - src/mono/wasm/host/* - src/mono/wasm/Wasm.Build.Tests/* - src/mono/nuget/Microsoft.NET.Runtime* src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/* diff --git a/src/mono/wasm/host/BrowserHost.cs b/src/mono/wasm/host/BrowserHost.cs index adb24f81f88dac..cbe160eeb0214a 100644 --- a/src/mono/wasm/host/BrowserHost.cs +++ b/src/mono/wasm/host/BrowserHost.cs @@ -74,7 +74,7 @@ private async Task RunAsync(ILoggerFactory loggerFactory, CancellationToken toke debugging: _args.CommonConfig.Debugging); runArgsJson.Save(Path.Combine(_args.CommonConfig.AppPath, "runArgs.json")); - string[] urls = envVars.TryGetValue("ASPNETCORE_URLS", out string? aspnetUrls) + string[] urls = (envVars.TryGetValue("ASPNETCORE_URLS", out string? aspnetUrls) && aspnetUrls.Length > 0) ? aspnetUrls.Split(';', StringSplitOptions.RemoveEmptyEntries) : new string[] { $"http://127.0.0.1:{_args.CommonConfig.HostProperties.WebServerPort}", "https://127.0.0.1:0" }; diff --git a/src/mono/wasm/host/DevServer/DevServer.cs b/src/mono/wasm/host/DevServer/DevServer.cs index 1acbe6954eeb3b..9a5a079cee695e 100644 --- a/src/mono/wasm/host/DevServer/DevServer.cs +++ b/src/mono/wasm/host/DevServer/DevServer.cs @@ -46,7 +46,8 @@ internal static class DevServer services.AddSingleton(Options.Create(options)); services.AddSingleton(realUrlsAvailableTcs); services.AddRouting(); - }); + }) + .UseUrls(options.Urls); IWebHost? host = builder.Build(); diff --git a/src/mono/wasm/host/RuntimeConfigJson.cs b/src/mono/wasm/host/RuntimeConfigJson.cs index ed698ed8fb3725..3ad30dd88015ae 100644 --- a/src/mono/wasm/host/RuntimeConfigJson.cs +++ b/src/mono/wasm/host/RuntimeConfigJson.cs @@ -24,7 +24,7 @@ internal sealed record WasmHostProperties( int? FirefoxDebuggingPort, int? ChromeProxyPort, int? ChromeDebuggingPort, - int WebServerPort = 9000) + int WebServerPort = 0) { // using an explicit property because the deserializer doesn't like // extension data in the record constructor From 937cfcdf13fdc5a8833807b49db4137a7970925e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:45:25 -0700 Subject: [PATCH 344/345] Update EventPipeEventDispatcher.cs (#92912) Co-authored-by: David Mason --- .../Tracing/EventPipeEventDispatcher.cs | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs index 708c5afc1bc70e..030560b2002145 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs @@ -103,8 +103,8 @@ private void CommitDispatchConfiguration() new EventPipeProviderConfiguration(NativeRuntimeEventSource.EventSourceName, (ulong)aggregatedKeywords, (uint)enableLevel, null) }; - m_sessionID = EventPipeInternal.Enable(null, EventPipeSerializationFormat.NetTrace, DefaultEventListenerCircularMBSize, providerConfiguration); - if (m_sessionID == 0) + ulong sessionID = EventPipeInternal.Enable(null, EventPipeSerializationFormat.NetTrace, DefaultEventListenerCircularMBSize, providerConfiguration); + if (sessionID == 0) { throw new EventSourceException(SR.EventSource_CouldNotEnableEventPipe); } @@ -113,7 +113,7 @@ private void CommitDispatchConfiguration() EventPipeSessionInfo sessionInfo; unsafe { - if (!EventPipeInternal.GetSessionInfo(m_sessionID, &sessionInfo)) + if (!EventPipeInternal.GetSessionInfo(sessionID, &sessionInfo)) { Debug.Fail("GetSessionInfo returned false."); } @@ -124,8 +124,11 @@ private void CommitDispatchConfiguration() long syncTimeQPC = sessionInfo.StartTimeStamp; long timeQPCFrequency = sessionInfo.TimeStampFrequency; + Debug.Assert(Volatile.Read(ref m_sessionID) == 0); + Volatile.Write(ref m_sessionID, sessionID); + // Start the dispatch task. - StartDispatchTask(m_sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency); + StartDispatchTask(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency); } private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency) @@ -147,10 +150,11 @@ private void SetStopDispatchTask() return; } - Debug.Assert(m_sessionID != 0); + ulong sessionID = Volatile.Read(ref m_sessionID); + Debug.Assert(sessionID != 0); m_dispatchTaskCancellationSource.Cancel(); - EventPipeInternal.SignalSession(m_sessionID); - m_sessionID = 0; + EventPipeInternal.SignalSession(sessionID); + Volatile.Write(ref m_sessionID, 0); } private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, Task? previousDispatchTask, CancellationToken token) @@ -190,12 +194,17 @@ private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syn } } - lock (m_dispatchControlLock) + // Wait for SignalSession() to be called before we call disable, otherwise + // the SignalSession() call could be on a disabled session. + SpinWait sw = default; + while (Volatile.Read(ref m_sessionID) == sessionID) { - // Disable the old session. This can happen asynchronously since we aren't using the old session - // anymore. We take the lock to make sure we don't call SignalSession on an invalid session ID. - EventPipeInternal.Disable(sessionID); + sw.SpinOnce(); } + + // Disable the old session. This can happen asynchronously since we aren't using the old session + // anymore. + EventPipeInternal.Disable(sessionID); } /// From b6222f400319b68532e4c1b2bed1b9eff095f6c9 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Tue, 3 Oct 2023 19:55:05 -0400 Subject: [PATCH 345/345] CI: runtime-wasm-perf: disable for PRs --- eng/pipelines/runtime-wasm-perf.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/pipelines/runtime-wasm-perf.yml b/eng/pipelines/runtime-wasm-perf.yml index bd6a6d979e3e40..69039fb3e2a473 100644 --- a/eng/pipelines/runtime-wasm-perf.yml +++ b/eng/pipelines/runtime-wasm-perf.yml @@ -3,6 +3,7 @@ # UI to this, and thus avoid any scheduled triggers trigger: none +pr: none variables: - template: /eng/pipelines/common/variables.yml