Skip to content

Commit

Permalink
.Net: Address IL2067 and IL3051 AOT warnings in Abstractions project (#…
Browse files Browse the repository at this point in the history
…9011)

### Motivation, Context and Description
This PR addresses the last two IL2067 and IL3051 AOT warnings in the
Abstractions project. It also adds the testing app that uses .NET’s AOT
compiler to analyze SK projects and ensure all AOT related warnings are
found. You can find more details here: -
https://devblogs.microsoft.com/dotnet/creating-aot-compatible-libraries/#analyzing-.net-libraries.
  • Loading branch information
SergeyMenshykh committed Sep 27, 2024
1 parent dace0bc commit 21f3ea5
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 10 deletions.
17 changes: 13 additions & 4 deletions dotnet/SK-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Diagnostics", "Diagnostics", "{29E7D971-1308-4171-9872-E8E4669A1134}"
ProjectSection(SolutionItems) = preProject
src\InternalUtilities\src\Diagnostics\CompilerServicesAttributes.cs = src\InternalUtilities\src\Diagnostics\CompilerServicesAttributes.cs
src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs = src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs
src\InternalUtilities\src\Diagnostics\ExceptionExtensions.cs = src\InternalUtilities\src\Diagnostics\ExceptionExtensions.cs
src\InternalUtilities\src\Diagnostics\ExperimentalAttribute.cs = src\InternalUtilities\src\Diagnostics\ExperimentalAttribute.cs
src\InternalUtilities\src\Diagnostics\IsExternalInit.cs = src\InternalUtilities\src\Diagnostics\IsExternalInit.cs
src\InternalUtilities\src\Diagnostics\NullableAttributes.cs = src\InternalUtilities\src\Diagnostics\NullableAttributes.cs
src\InternalUtilities\src\Diagnostics\Verify.cs = src\InternalUtilities\src\Diagnostics\Verify.cs
src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs = src\InternalUtilities\src\Diagnostics\DynamicallyAccessedMembersAttribute.cs
src\InternalUtilities\src\Diagnostics\RequiresDynamicCodeAttribute.cs = src\InternalUtilities\src\Diagnostics\RequiresDynamicCodeAttribute.cs
src\InternalUtilities\src\Diagnostics\RequiresUnreferencedCodeAttribute.cs = src\InternalUtilities\src\Diagnostics\RequiresUnreferencedCodeAttribute.cs
src\InternalUtilities\src\Diagnostics\UnconditionalSuppressMessageAttribute.cs = src\InternalUtilities\src\Diagnostics\UnconditionalSuppressMessageAttribute.cs
src\InternalUtilities\src\Diagnostics\Verify.cs = src\InternalUtilities\src\Diagnostics\Verify.cs
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linq", "Linq", "{B00AD427-0047-4850-BEF9-BA8237EA9D8B}"
Expand Down Expand Up @@ -364,7 +364,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Process.LocalRuntime", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Process.UnitTests", "src\Experimental\Process.UnitTests\Process.UnitTests.csproj", "{21A32285-8443-4A75-B2E8-27E6090EC562}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStartedWithProcesses", "samples\GettingStartedWithProcesses\GettingStartedWithProcesses.csproj", "{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GettingStartedWithProcesses", "samples\GettingStartedWithProcesses\GettingStartedWithProcesses.csproj", "{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AotCompatibility.TestApp", "samples\Demos\AotCompatibility.TestApp\AotCompatibility.TestApp.csproj", "{6ECFDF04-2237-4A85-B114-DAA34923E9E6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -931,6 +933,12 @@ Global
{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}.Publish|Any CPU.Build.0 = Debug|Any CPU
{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7}.Release|Any CPU.Build.0 = Release|Any CPU
{6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Publish|Any CPU.ActiveCfg = Publish|Any CPU
{6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Publish|Any CPU.Build.0 = Publish|Any CPU
{6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6ECFDF04-2237-4A85-B114-DAA34923E9E6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1059,8 +1067,9 @@ Global
{27AF60D6-86F5-4591-A700-4F8C93F41B11} = {0D8C6358-5DAA-4EA6-A924-C268A9A21BC9}
{21A32285-8443-4A75-B2E8-27E6090EC562} = {0D8C6358-5DAA-4EA6-A924-C268A9A21BC9}
{C057ACDF-DDD8-496B-BAF9-1C6E4E1248D7} = {FA3720F1-C99A-49B2-9577-A940257098BF}
{6ECFDF04-2237-4A85-B114-DAA34923E9E6} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FBDC56A3-86AD-4323-AA0F-201E59123B83}
EndGlobalSection
EndGlobal
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions dotnet/samples/Demos/AotCompatibility.TestApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.

namespace AotCompatibility.TestApp;

internal static class Program
{
private static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
10 changes: 6 additions & 4 deletions dotnet/src/InternalUtilities/src/System/InternalTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,19 @@ internal static class InternalTypeConverter
/// </summary>
/// <param name="sourceType">The source Type for which to retrieve the type-to-string converter delegate.</param>
/// <returns>A Func delegate for converting the source type to a string, considering CultureInfo, or null if no suitable converter is found.</returns>
private static Func<object?, CultureInfo, string?>? GetTypeToStringConverterDelegate(Type sourceType) =>
s_converters.GetOrAdd(sourceType, static sourceType =>
private static Func<object?, CultureInfo, string?>? GetTypeToStringConverterDelegate(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] Type sourceType) =>
s_converters.GetOrAdd(sourceType, (
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] Type innerSourceType) =>
{
// Strings just render as themselves.
if (sourceType == typeof(string))
if (innerSourceType == typeof(string))
{
return (input, cultureInfo) => (string)input!;
}
// Look up and use a type converter.
if (TypeConverterFactory.GetTypeConverter(sourceType) is TypeConverter converter && converter.CanConvertTo(typeof(string)))
if (TypeConverterFactory.GetTypeConverter(innerSourceType) is TypeConverter converter && converter.CanConvertTo(typeof(string)))
{
return (input, cultureInfo) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ internal static class TypeConverterFactory
/// </summary>
/// <param name="type">The Type of the object to convert.</param>
/// <returns>A TypeConverter instance if a suitable converter is found, otherwise null.</returns>
internal static TypeConverter? GetTypeConverter(Type type)
internal static TypeConverter? GetTypeConverter(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] Type type)
{
// In an ideal world, this would use TypeDescriptor.GetConverter. However, that is not friendly to
// any form of ahead-of-time compilation, as it could end up requiring functionality that was trimmed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.SemanticKernel;
Expand Down Expand Up @@ -32,9 +33,29 @@ public object GetRequiredKeyedService(Type serviceType, object? serviceKey) =>
if (serviceType.IsConstructedGenericType &&
serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
return Array.CreateInstance(serviceType.GenericTypeArguments[0], 0);
return CreateArray(serviceType.GenericTypeArguments[0], 0);
}

return null;
}

[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "VerifyAotCompatibility ensures elementType is not a ValueType")]
private static Array CreateArray(Type elementType, int length)
{
if (VerifyAotCompatibility && elementType.IsValueType)
{
// NativeAOT apps are not able to make Enumerable of ValueType services
// since there is no guarantee the ValueType[] code has been generated.
throw new InvalidOperationException($"Unable to create an Enumerable service of type '{elementType}' because it is a ValueType. Native code to support creating Enumerable services might not be available with native AOT.");
}

return Array.CreateInstance(elementType, length);
}

private static bool VerifyAotCompatibility =>
#if NETFRAMEWORK || NETSTANDARD2_0
false;
#else
!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported;
#endif
}

0 comments on commit 21f3ea5

Please sign in to comment.