From b5b54ec5de5ac5a695dae73ec594096cff3a0dae Mon Sep 17 00:00:00 2001 From: sakno Date: Sun, 28 Jan 2024 19:53:21 +0200 Subject: [PATCH 1/5] Migration to collection literals --- .../Expressions/CollectionAccessExpression.cs | 6 +++--- .../Linq/Expressions/ExpressionBuilder.cs | 6 +++--- .../Expressions/InterpolationExpression.cs | 8 +++---- .../Linq/Expressions/ItemIndexExpression.cs | 2 +- .../Linq/Expressions/LockExpression.cs | 4 ++-- .../Linq/Expressions/MetaExpression.cs | 2 +- .../Linq/Expressions/MutationExpression.cs | 4 ++-- .../NullCoalescingAssignmentExpression.cs | 2 +- .../Linq/Expressions/RangeExpression.cs | 2 +- .../Linq/Expressions/RefAnyValExpression.cs | 2 +- .../Linq/Expressions/SliceExpression.cs | 6 +++--- .../Linq/Expressions/WriteLineExpression.cs | 4 ++-- .../Metaprogramming/MatchBuilder.cs | 8 +++---- .../AsyncStateMachineBuilder.cs | 2 +- .../InterpolatedStringTemplateBuilder.cs | 21 +++++-------------- .../CompilerServices/MoveNextExpression.cs | 2 +- 16 files changed, 35 insertions(+), 46 deletions(-) diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs index 90ac36a392..86f4787a3a 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs @@ -138,11 +138,11 @@ public override Expression Reduce() if (indexer is null) result = ArrayAccess(temp ?? Collection, Index); else if (count is null) - result = MakeIndex(temp ?? Collection, indexer, new[] { Index.Reduce() }); + result = MakeIndex(temp ?? Collection, indexer, [Index.Reduce()]); else - result = MakeIndex(temp ?? Collection, indexer, new[] { MakeIndex(temp ?? Collection, count, Index) }); + result = MakeIndex(temp ?? Collection, indexer, [MakeIndex(temp ?? Collection, count, Index)]); - return temp is null ? result : Block(Type, new[] { temp }, Assign(temp, Collection), result); + return temp is null ? result : Block(Type, [temp], Assign(temp, Collection), result); } /// diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs b/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs index 172c2fcb5d..9ad3e4eed3 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs @@ -1206,7 +1206,7 @@ internal static Expression AddEpilogue(this Expression expression, bool inferTyp [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(Activator))] public static MethodCallExpression New(this Expression type, params Expression[] args) { - var activate = typeof(Activator).GetMethod(nameof(Activator.CreateInstance), new[] { typeof(Type), typeof(object[]) }); + var activate = typeof(Activator).GetMethod(nameof(Activator.CreateInstance), [typeof(Type), typeof(object[])]); Debug.Assert(activate is not null); return Expression.Call(activate, type, Expression.NewArrayInit(typeof(object), args)); } @@ -1456,9 +1456,9 @@ public static Expression AsOptional(this Expression expression) public static Expression AsResult(this Expression expression) { var exception = Expression.Parameter(typeof(Exception)); - var ctor = typeof(Result<>).MakeGenericType(expression.Type).GetConstructor(new[] { expression.Type }); + var ctor = typeof(Result<>).MakeGenericType(expression.Type).GetConstructor([expression.Type]); Debug.Assert(ctor?.DeclaringType is not null); - var fallbackCtor = ctor.DeclaringType.GetConstructor(new[] { typeof(Exception) }); + var fallbackCtor = ctor.DeclaringType.GetConstructor([typeof(Exception)]); Debug.Assert(fallbackCtor is not null); return Expression.TryCatch( Expression.New(ctor, expression), diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/InterpolationExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/InterpolationExpression.cs index 76d983426f..aa8f1b3f85 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/InterpolationExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/InterpolationExpression.cs @@ -105,19 +105,19 @@ private Expression MakePlainString() case 0: return Constant(Format); case 1: - var formatMethod = typeof(string).GetMethod(nameof(string.Format), new[] { typeof(IFormatProvider), typeof(string), typeof(object) }); + var formatMethod = typeof(string).GetMethod(nameof(string.Format), [typeof(IFormatProvider), typeof(string), typeof(object)]); Debug.Assert(formatMethod is not null); return Call(formatMethod, FormatProvider, Constant(Format), arguments[0]); case 2: - formatMethod = typeof(string).GetMethod(nameof(string.Format), new[] { typeof(IFormatProvider), typeof(string), typeof(object), typeof(object) }); + formatMethod = typeof(string).GetMethod(nameof(string.Format), [typeof(IFormatProvider), typeof(string), typeof(object), typeof(object)]); Debug.Assert(formatMethod is not null); return Call(formatMethod, FormatProvider, Constant(Format), FormatProvider, arguments[0], arguments[1]); case 3: - formatMethod = typeof(string).GetMethod(nameof(string.Format), new[] { typeof(IFormatProvider), typeof(string), typeof(object), typeof(object), typeof(object) }); + formatMethod = typeof(string).GetMethod(nameof(string.Format), [typeof(IFormatProvider), typeof(string), typeof(object), typeof(object), typeof(object)]); Debug.Assert(formatMethod is not null); return Call(formatMethod, FormatProvider, Constant(Format), FormatProvider, arguments[0], arguments[1], arguments[2]); default: - formatMethod = typeof(string).GetMethod(nameof(string.Format), new[] { typeof(IFormatProvider), typeof(string), typeof(object[]) }); + formatMethod = typeof(string).GetMethod(nameof(string.Format), [typeof(IFormatProvider), typeof(string), typeof(object[])]); Debug.Assert(formatMethod is not null); return Call(formatMethod, FormatProvider, Constant(Format), FormatProvider, NewArrayInit(typeof(object), arguments)); } diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs index 0aafdb8350..1369ac13c3 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs @@ -74,7 +74,7 @@ internal static Expression GetOffset(Expression index, Expression count) /// Translated expression. public override Expression Reduce() { - ConstructorInfo? ctor = typeof(Index).GetConstructor(new[] { typeof(int), typeof(bool) }); + ConstructorInfo? ctor = typeof(Index).GetConstructor([typeof(int), typeof(bool)]); Debug.Assert(ctor is not null); return New(ctor, conversionRequired ? Convert(Value, typeof(int)) : Value, Constant(IsFromEnd)); } diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/LockExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/LockExpression.cs index 36252f1fb8..e360d689e3 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/LockExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/LockExpression.cs @@ -94,9 +94,9 @@ public Expression Body [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(Monitor))] public override Expression Reduce() { - var monitorEnter = typeof(Monitor).GetMethod(nameof(Monitor.Enter), new[] { typeof(object) }); + var monitorEnter = typeof(Monitor).GetMethod(nameof(Monitor.Enter), [typeof(object)]); Debug.Assert(monitorEnter is not null); - var monitorExit = typeof(Monitor).GetMethod(nameof(Monitor.Exit), new[] { typeof(object) }); + var monitorExit = typeof(Monitor).GetMethod(nameof(Monitor.Exit), [typeof(object)]); Debug.Assert(monitorExit is not null); var body = TryFinally(Body, Call(monitorExit, SyncRoot)); return assignment is null ? diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs index 8122eb1a75..37b2245a30 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs @@ -70,7 +70,7 @@ private static Expression ToExpression(DynamicMetaObject arg, out BindingRestric } } - return Expression.Call(typeof(ExpressionBuilder), nameof(ExpressionBuilder.Const), new[] { arg.Expression.Type }, arg.Expression); + return Expression.Call(typeof(ExpressionBuilder), nameof(ExpressionBuilder.Const), [arg.Expression.Type], arg.Expression); } private static IReadOnlyList ToExpressions(DynamicMetaObject[] args, out BindingRestrictions restrictions) diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/MutationExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/MutationExpression.cs index b71612d158..0d602e79bf 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/MutationExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/MutationExpression.cs @@ -95,13 +95,13 @@ public override Expression Reduce() if (Bindings.Count > 0) { var tempVar = Parameter(Type, "copy"); - ICollection statements = new List(Bindings.Count + 2) { Assign(tempVar, result) }; + List statements = new(Bindings.Count + 2) { Assign(tempVar, result) }; foreach (var binding in Bindings) statements.Add(Assign(MakeMemberAccess(tempVar, binding.Member), binding.Expression)); statements.Add(tempVar); - result = Block(tempVar.Type, new[] { tempVar }, statements); + result = Block(tempVar.Type, [tempVar], statements); } return result; diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/NullCoalescingAssignmentExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/NullCoalescingAssignmentExpression.cs index c35fe0eca5..b0faa95be9 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/NullCoalescingAssignmentExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/NullCoalescingAssignmentExpression.cs @@ -84,7 +84,7 @@ public override Expression Reduce() return Block( Left.Type, - new[] { localVar }, + [localVar], Assign(localVar, Left), Assign(Left, Build(localVar, Right)), localVar); diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/RangeExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/RangeExpression.cs index 65a7f8600c..a44c20af7c 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/RangeExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/RangeExpression.cs @@ -56,7 +56,7 @@ internal static Expression GetOffsetAndLength(Expression range, Expression lengt /// Translated expression. public override Expression Reduce() { - ConstructorInfo? ctor = typeof(Range).GetConstructor(new[] { typeof(Index), typeof(Index) }); + ConstructorInfo? ctor = typeof(Range).GetConstructor([typeof(Index), typeof(Index)]); Debug.Assert(ctor is not null); return New(ctor, Start.Reduce(), End.Reduce()); } diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/RefAnyValExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/RefAnyValExpression.cs index 7fa48cab01..b03c4e2793 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/RefAnyValExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/RefAnyValExpression.cs @@ -42,5 +42,5 @@ public RefAnyValExpression(ParameterExpression typedRef, Type referenceType) /// using Lowering technique. /// /// Translated expression. - public override Expression Reduce() => Call(typeof(Intrinsics), nameof(Intrinsics.AsRef), new[] { ReferenceType }, TypedReferenceVar); + public override Expression Reduce() => Call(typeof(Intrinsics), nameof(Intrinsics.AsRef), [ReferenceType], TypedReferenceVar); } \ No newline at end of file diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/SliceExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/SliceExpression.cs index bb2fee5fb6..68abb4b285 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/SliceExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/SliceExpression.cs @@ -99,7 +99,7 @@ private static IEnumerable GetSliceMethods(Type collection) [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(RuntimeHelpers))] private static MethodCallExpression SubArray(Expression array, Expression range) { - MethodInfo? subArray = typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.GetSubArray), 1, new[] { Type.MakeGenericMethodParameter(0).MakeArrayType(), typeof(Range) }); + MethodInfo? subArray = typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.GetSubArray), 1, [Type.MakeGenericMethodParameter(0).MakeArrayType(), typeof(Range)]); Debug.Assert(subArray is not null); subArray = subArray.MakeGenericMethod(array.Type.GetElementType()!); return Call(subArray, array, range.Reduce()); @@ -108,7 +108,7 @@ private static MethodCallExpression SubArray(Expression array, Expression range) private static BlockExpression SubCollection(Expression collection, MethodInfo slice, PropertyInfo count, Expression range) { var offsetAndLengthCall = RangeExpression.GetOffsetAndLength(range, Property(collection, count), out var offsetAndLength, out var offsetField, out var lengthField); - return Block(new[] { offsetAndLength }, Assign(offsetAndLength, offsetAndLengthCall), Call(collection, slice, offsetField, lengthField)); + return Block([offsetAndLength], Assign(offsetAndLength, offsetAndLengthCall), Call(collection, slice, offsetField, lengthField)); } /// @@ -127,7 +127,7 @@ public override Expression Reduce() else result = SubCollection(temp ?? Collection, slice, count, Range); - return temp is null ? result : Block(Type, new[] { temp }, Assign(temp, Collection), result); + return temp is null ? result : Block(Type, [temp], Assign(temp, Collection), result); } /// diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/WriteLineExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/WriteLineExpression.cs index b8a4a37e32..49dfd35b7f 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/WriteLineExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/WriteLineExpression.cs @@ -60,7 +60,7 @@ private WriteLineExpression(Expression value, Kind kind) [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(TextWriter))] private static MethodCallExpression WriteLineTo(MemberExpression stream, Expression value) { - MethodInfo? writeLineMethod = typeof(TextWriter).GetMethod(nameof(TextWriter.WriteLine), new[] { value.Type }); + MethodInfo? writeLineMethod = typeof(TextWriter).GetMethod(nameof(TextWriter.WriteLine), [value.Type]); // WriteLine method will always be resolved here because Type.DefaultBinder // chooses TextWriter.WriteLine(object) if there is no exact match @@ -91,7 +91,7 @@ private MethodCallExpression WriteLineToError() [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(System.Diagnostics.Debug))] private MethodCallExpression WriteLineToDebug() { - var writeLineMethod = typeof(System.Diagnostics.Debug).GetMethod(nameof(System.Diagnostics.Debug.WriteLine), new[] { typeof(object) }); + var writeLineMethod = typeof(System.Diagnostics.Debug).GetMethod(nameof(System.Diagnostics.Debug.WriteLine), [typeof(object)]); System.Diagnostics.Debug.Assert(writeLineMethod is not null); return Call(writeLineMethod, value.Type.IsValueType ? Convert(value, typeof(object)) : value); } diff --git a/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs b/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs index 4ce80f4a9f..1ceeabeb65 100644 --- a/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs +++ b/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs @@ -193,7 +193,7 @@ public MatchBuilder Case(string memberName, Expression memberValue, FuncThe action to be executed if object matches to the pattern. /// this builder. public MatchBuilder Case(string memberName1, Expression memberValue1, string memberName2, Expression memberValue2, Func body) - => Case(StructuralPattern(new[] { (memberName1, memberValue1), (memberName2, memberValue2) }), value => body(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2))); + => Case(StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2)]), value => body(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2))); /// /// Defines pattern matching based on structural matching. @@ -207,7 +207,7 @@ public MatchBuilder Case(string memberName1, Expression memberValue1, string mem /// The action to be executed if object matches to the pattern. /// this builder. public MatchBuilder Case(string memberName1, Expression memberValue1, string memberName2, Expression memberValue2, string memberName3, Expression memberValue3, Func body) - => Case(StructuralPattern(new[] { (memberName1, memberValue1), (memberName2, memberValue2), (memberName3, memberValue3) }), value => body(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2), Expression.PropertyOrField(value, memberName3))); + => Case(StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2), (memberName3, memberValue3)]), value => body(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2), Expression.PropertyOrField(value, memberName3))); private static (string, Expression) GetMemberPattern(object @this, string memberName, Type memberType, Func valueProvider) { @@ -545,7 +545,7 @@ internal MatchByTwoMembersStatement(MatchBuilder builder, string memberName1, Ex private protected override MatchBuilder Build(MatchBuilder builder, Action scope) { - var pattern = StructuralPattern(new[] { (memberName1, memberValue1), (memberName2, memberValue2) }); + var pattern = StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2)]); return builder.MatchByCondition(pattern, new CaseStatementBuilder(this, memberName1, memberName2, scope)); } } @@ -591,7 +591,7 @@ internal MatchByThreeMembersStatement(MatchBuilder builder, string memberName1, private protected override MatchBuilder Build(MatchBuilder builder, Action scope) { - var pattern = StructuralPattern(new[] { (memberName1, memberValue1), (memberName2, memberValue2), (memberName3, memberValue3) }); + var pattern = StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2), (memberName3, memberValue3)]); return builder.MatchByCondition(pattern, new CaseStatementBuilder(this, memberName1, memberName2, memberName3, scope)); } } diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs index 7af7fe79e6..e76b71c499 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs @@ -495,7 +495,7 @@ private Expression Build(LambdaExpression stateMachineMethod) var startMethod = stateMachine.Type.GetMethod(nameof(AsyncStateMachine.Start)); Debug.Assert(startMethod is not null); newBody.Add(methodBuilder.Task.AdjustTaskType(Expression.Call(startMethod, stateMachineMethod, stateVariable))); - return Expression.Lambda(Expression.Block(new[] { stateVariable }, newBody), true, parameters); + return Expression.Lambda(Expression.Block([stateVariable], newBody), true, parameters); } private sealed class StateMachineBuilder diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs index 7c1ccb0c81..809a71ee78 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs @@ -13,9 +13,11 @@ namespace DotNext.Runtime.CompilerServices; /// Represents a builder of the lambda expression /// that can be compiled to the renderer of the interpolated string. /// +/// The total number of characters in known at compile-time. +/// The number of placeholders. [InterpolatedStringHandler] [StructLayout(LayoutKind.Auto)] -public struct InterpolatedStringTemplateBuilder +public struct InterpolatedStringTemplateBuilder(int literalLength, int formattedCount) { [StructLayout(LayoutKind.Auto)] private readonly struct Segment @@ -95,20 +97,7 @@ internal void WriteTo(scoped ref int position, scoped ref BufferWriterSlim } } - private readonly int literalLength, formattedCount; - private List? segments; - - /// - /// Initializes a new builder. - /// - /// The total number of characters in known at compile-time. - /// The number of placeholders. - public InterpolatedStringTemplateBuilder(int literalLength, int formattedCount) - { - segments = new(formattedCount); - this.literalLength = literalLength; - this.formattedCount = formattedCount; - } + private List? segments = new(formattedCount); [DebuggerBrowsable(DebuggerBrowsableState.Never)] private List Segments => segments ??= []; @@ -207,7 +196,7 @@ public readonly LambdaExpression Build() // try-finally block to dispose the writer expr = Expression.Block(statements); expr = Expression.TryFinally(expr, Expression.Call(writerLocal, nameof(BufferWriterSlim.Dispose), [])); - expr = Expression.Block(new[] { preallocatedBufferLocal, writerLocal, handlerLocal }, expr); + expr = Expression.Block([preallocatedBufferLocal, writerLocal, handlerLocal], expr); return Expression.Lambda( expr, diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/MoveNextExpression.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/MoveNextExpression.cs index 852a9b5702..2e43ceb982 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/MoveNextExpression.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/MoveNextExpression.cs @@ -31,7 +31,7 @@ internal override Expression Reduce(ParameterExpression stateMachine) { const BindingFlags PublicInstanceFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; var genericParam = Type.MakeGenericMethodParameter(0).MakeByRefType(); - var moveNext = stateMachine.Type.GetMethod(nameof(AsyncStateMachine.MoveNext), 1, PublicInstanceFlags, null, new[] { genericParam, typeof(uint) }, null)!.MakeGenericMethod(awaiter.Type); + var moveNext = stateMachine.Type.GetMethod(nameof(AsyncStateMachine.MoveNext), 1, PublicInstanceFlags, null, [genericParam, typeof(uint)], null)!.MakeGenericMethod(awaiter.Type); return stateMachine.Call(moveNext, awaiter, StateId); } } \ No newline at end of file From eb50f25a2da551dd9f341c9485d6a46560b6c720 Mon Sep 17 00:00:00 2001 From: sakno Date: Sun, 28 Jan 2024 19:55:42 +0200 Subject: [PATCH 2/5] Fixed compiler warning --- .../Runtime/CompilerServices/AsyncStateMachineBuilder.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs index e76b71c499..b7aa4ff015 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Runtime.CompilerServices; -using static System.Diagnostics.Debug; using static System.Linq.Enumerable; namespace DotNext.Runtime.CompilerServices; @@ -457,7 +456,7 @@ private static MemberExpression GetStateField(ParameterExpression stateMachine) private Expression Build(LambdaExpression stateMachineMethod) { - Assert(stateMachine is not null); + Debug.Assert(stateMachine is not null); var stateVariable = Expression.Variable(GetStateField(stateMachine).Type); var parameters = methodBuilder.Parameters; ICollection newBody = new LinkedList(); @@ -550,7 +549,7 @@ private static MemberExpression[] CreateStateHolderType(Type returnType, bool us slots = builder.Build(sm.Build, out _); } - Assert(sm.StateMachine is not null); + Debug.Assert(sm.StateMachine is not null); stateMachine = sm.StateMachine; return slots; } @@ -583,7 +582,7 @@ protected override Expression VisitParameter(ParameterExpression node) protected override Expression VisitExtension(Expression node) { - Assert(stateMachine is not null); + Debug.Assert(stateMachine is not null); return node switch { StatePlaceholderExpression placeholder => placeholder.Reduce(), From 99166104f513bf0ca2ec7fa4f43846d247d734ad Mon Sep 17 00:00:00 2001 From: sakno Date: Sun, 28 Jan 2024 21:59:46 +0200 Subject: [PATCH 3/5] Initial work for IL trimming --- .../DotNext.Metaprogramming.csproj | 4 +-- .../Linq/Expressions/ExpressionBuilder.cs | 27 ++++++++++++++----- .../Linq/Expressions/ForEachExpression.cs | 2 ++ .../Linq/Expressions/ItemIndexExpression.cs | 3 +++ .../Linq/Expressions/MemberBindings.cs | 3 ++- .../AsyncStateMachineBuilder.cs | 11 ++++---- .../CompilerServices/ClosureAnalyzer.cs | 1 + .../InterpolatedStringTemplateBuilder.cs | 19 ++++++++++--- 8 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/DotNext.Metaprogramming/DotNext.Metaprogramming.csproj b/src/DotNext.Metaprogramming/DotNext.Metaprogramming.csproj index 9cbc9292f7..e62aa45b4e 100644 --- a/src/DotNext.Metaprogramming/DotNext.Metaprogramming.csproj +++ b/src/DotNext.Metaprogramming/DotNext.Metaprogramming.csproj @@ -6,9 +6,9 @@ latest enable true - false + true nullablePublicOnly - 5.0.1 + 5.0.2 .NET Foundation .NEXT Family of Libraries diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs b/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs index 9ad3e4eed3..f479ab686c 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/ExpressionBuilder.cs @@ -251,6 +251,7 @@ public static BinaryExpression NotEqual(this Expression left, Expression right) /// /// The operand. /// check operation. + [RequiresUnreferencedCode("Dynamic access to properties of .")] public static Expression IsNull(this Expression operand) { // handle nullable value type @@ -277,6 +278,7 @@ public static Expression IsNull(this Expression operand) /// /// The operand. /// check operation. + [RequiresUnreferencedCode("Dynamic access to properties of .")] public static Expression IsNotNull(this Expression operand) { // handle nullable value type @@ -723,6 +725,7 @@ public static MethodCallExpression Call(this Expression instance, MethodInfo met /// The name of the method to be called. /// The method arguments. /// The method call expression. + [RequiresUnreferencedCode("Dynamic access to the method identified by parameter.")] public static MethodCallExpression Call(this Expression instance, string methodName, params Expression[] arguments) => instance.Call(instance.Type, methodName, arguments); @@ -739,7 +742,7 @@ public static MethodCallExpression Call(this Expression instance, string methodN /// The name of the method in the interface or base class to be called. /// The method arguments. /// The method call expression. - public static MethodCallExpression Call(this Expression instance, Type interfaceType, string methodName, params Expression[] arguments) + public static MethodCallExpression Call(this Expression instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type interfaceType, string methodName, params Expression[] arguments) { if (!interfaceType.IsAssignableFrom(instance.Type)) throw new ArgumentException(ExceptionMessages.InterfaceNotImplemented(instance.Type, interfaceType)); @@ -756,7 +759,7 @@ public static MethodCallExpression Call(this Expression instance, Type interface /// The name of the static method. /// The arguments to be passed into static method. /// An expression representing static method call. - public static MethodCallExpression CallStatic(this Type type, string methodName, params Expression[] arguments) + public static MethodCallExpression CallStatic([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] this Type type, string methodName, params Expression[] arguments) { return type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly, null, Array.ConvertAll(arguments, GetType), null) is { } method ? Expression.Call(method, arguments) @@ -799,7 +802,7 @@ public static IndexExpression Property(this Expression instance, PropertyInfo pr /// The interface or base class declaring property. /// The name of the instance property. /// Property access expression. - public static MemberExpression Property(this Expression instance, Type interfaceType, string propertyName) + public static MemberExpression Property(this Expression instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type interfaceType, string propertyName) { return interfaceType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance) is { } property ? Property(instance, property) @@ -818,7 +821,7 @@ public static MemberExpression Property(this Expression instance, Type interface /// The first index. /// The rest of the indexer arguments. /// Property access expression. - public static IndexExpression Property(this Expression instance, Type interfaceType, string propertyName, Expression index0, params Expression[] indicies) + public static IndexExpression Property(this Expression instance, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type interfaceType, string propertyName, Expression index0, params Expression[] indicies) { return interfaceType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance) is { } property ? Property(instance, property, index0, indicies) @@ -834,6 +837,7 @@ public static IndexExpression Property(this Expression instance, Type interfaceT /// this argument. /// The name of the instance property. /// Property access expression. + [RequiresUnreferencedCode("Dynamic access to the property identified by parameter.")] public static MemberExpression Property(this Expression instance, string propertyName) => Expression.Property(instance, propertyName); @@ -848,6 +852,7 @@ public static MemberExpression Property(this Expression instance, string propert /// The first index. /// The rest of the indexer arguments. /// Property access expression. + [RequiresUnreferencedCode("Dynamic access to the indexer identified by parameter.")] public static IndexExpression Property(this Expression instance, string propertyName, Expression index0, params Expression[] indicies) => Expression.Property(instance, propertyName, [index0, .. indicies]); @@ -872,6 +877,7 @@ public static MemberExpression Field(this Expression instance, FieldInfo field) /// this argument. /// The name of the instance field. /// Field access expression. + [RequiresUnreferencedCode("Dynamic access to the field identified by parameter.")] public static MemberExpression Field(this Expression instance, string fieldName) => Expression.Field(instance, fieldName); @@ -937,10 +943,12 @@ public static UnaryExpression ArrayLength(this Expression array) /// /// The expression representing collection. /// The expression providing access to the appropriate property indicating the number of items in the collection. + [RequiresUnreferencedCode("Dynamic access to implemented interfaces and public properties of .")] public static MemberExpression Count(this Expression collection) { if (collection.Type == typeof(string) || collection.Type == typeof(StringBuilder)) return Expression.Property(collection, nameof(string.Length)); + var interfaceType = collection.Type.GetImplementedCollection() ?? throw new ArgumentException(ExceptionMessages.CollectionImplementationExpected); return Expression.Property(collection, interfaceType, nameof(Count)); } @@ -950,6 +958,7 @@ public static MemberExpression Count(this Expression collection) /// /// The object to be converted into string. /// The expression representing ToString() method call. + [RequiresUnreferencedCode("Dynamic access to public methods of .")] public static MethodCallExpression AsString(this Expression obj) => Call(obj, nameof(ToString)); /// @@ -1136,12 +1145,12 @@ public static ConditionalExpression Condition(this Expression test, Exp /// The type to be instantiated. /// The list of arguments to be passed into constructor. /// Instantiation expression. - public static NewExpression New(this Type type, params Expression[] args) + public static NewExpression New([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] this Type type, params Expression[] args) { if (args.LongLength is 0L) return Expression.New(type); - return type.GetConstructor(Array.ConvertAll(args, static arg => arg.Type)) is { } ctor + return type.GetConstructor(Array.ConvertAll(args, GetType)) is { } ctor ? Expression.New(ctor, args) : throw new MissingMethodException(type.FullName, ConstructorInfo.ConstructorName); } @@ -1155,6 +1164,7 @@ public static NewExpression New(this Type type, params Expression[] args) /// An expression representing object construction. /// A collection of members to initialize. /// Initialization expression. + [RequiresUnreferencedCode("Dynamic access to public properties of .")] public static MemberInitExpression Init(this NewExpression expression, MemberBindings bindings) => Expression.MemberInit(expression, bindings.Bind(expression.Type)); @@ -1203,7 +1213,7 @@ internal static Expression AddEpilogue(this Expression expression, bool inferTyp /// The expression representing the type to be instantiated. /// The list of arguments to be passed into constructor. /// Instantiation expression. - [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(Activator))] + [RequiresUnreferencedCode("Dynamic access to public constructors of a type represented by .")] public static MethodCallExpression New(this Expression type, params Expression[] args) { var activate = typeof(Activator).GetMethod(nameof(Activator.CreateInstance), [typeof(Type), typeof(object[])]); @@ -1217,6 +1227,7 @@ public static MethodCallExpression New(this Expression type, params Expression[] /// The collection to iterate through. /// A delegate that is used to construct the body of the loop. /// The constructed loop. + [RequiresUnreferencedCode("Dynamic access to GetEnumerator method and IEnumerable interfaces.")] public static ForEachExpression ForEach(this Expression collection, ForEachExpression.Statement body) => ForEachExpression.Create(collection, body); @@ -1453,6 +1464,7 @@ public static Expression AsOptional(this Expression expression) /// /// The compound expression. /// The expression of type . + [RequiresUnreferencedCode("Dynamic access to DotNext.Result<> data type")] public static Expression AsResult(this Expression expression) { var exception = Expression.Parameter(typeof(Exception)); @@ -1465,6 +1477,7 @@ public static Expression AsResult(this Expression expression) Expression.Catch(exception, Expression.New(fallbackCtor, exception))); } + [RequiresUnreferencedCode("Dynamic access to indexer of .")] internal static IndexExpression MakeIndex(Expression target, Expression[] args) { // handle case for array diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs index 373c0bc410..810a761a2e 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; @@ -13,6 +14,7 @@ namespace DotNext.Linq.Expressions; /// Represents iteration over collection elements as expression. /// /// foreach Statement +[RequiresUnreferencedCode("Dynamic access to GetEnumerator method and IEnumerable interfaces.")] public sealed class ForEachExpression : CustomExpression, ILoopLabels { private const string EnumeratorVarName = "enumerator"; diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs index 1369ac13c3..af52a8a532 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/ItemIndexExpression.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; using Debug = System.Diagnostics.Debug; @@ -64,6 +65,8 @@ public ItemIndexExpression(Expression value, bool fromEnd = false) /// public override Type Type => typeof(Index); + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(Index))] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Dependency of Index is declared explicitly")] internal static Expression GetOffset(Expression index, Expression count) => index is ItemIndexExpression { IsFromEnd: false } itemIndex ? itemIndex.Value : Call(index, nameof(Index.GetOffset), null, count); diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/MemberBindings.cs b/src/DotNext.Metaprogramming/Linq/Expressions/MemberBindings.cs index 9b22273ef8..f8b0bb4458 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/MemberBindings.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/MemberBindings.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; @@ -21,7 +22,7 @@ public MemberBindings() /// /// The target type with the declared members. /// A list of bindings. - public IReadOnlyList Bind(Type target) + public IReadOnlyList Bind([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type target) { const MemberTypes memberTypes = MemberTypes.Field | MemberTypes.Property; const BindingFlags memberFlags = BindingFlags.Public | BindingFlags.Instance; diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs index b7aa4ff015..f54f19522b 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/AsyncStateMachineBuilder.cs @@ -21,6 +21,7 @@ namespace DotNext.Runtime.CompilerServices; /// 2. Construct state holder type /// 3. Replace all local variables with fields from state holder type. /// +[RequiresUnreferencedCode("Dynamic access to DotNext.Metaprogramming internal types, Task and ValueTask.")] internal sealed class AsyncStateMachineBuilder : ExpressionVisitor, IDisposable { private static readonly UserDataSlot ParameterPositionSlot = new(); @@ -57,7 +58,7 @@ internal AsyncStateMachineBuilder(Type taskType, IReadOnlyList : ExpressionVisitor, IDisposable +[RequiresUnreferencedCode("Dynamic access to Transition and IAsyncStateMachine internal types.")] +internal sealed class AsyncStateMachineBuilder<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate> : ExpressionVisitor, IDisposable where TDelegate : Delegate { private readonly AsyncStateMachineBuilder methodBuilder; @@ -509,10 +511,7 @@ internal StateMachineBuilder(Type returnType, bool usePooling) this.usePooling = usePooling; } - [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(AsyncStateMachine<>))] - [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(AsyncStateMachine<,>))] - [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PoolingAsyncStateMachine<>))] - [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PoolingAsyncStateMachine<,>))] + [RequiresUnreferencedCode("Dynamic access to AsyncStateMachine and PoolingAsyncStateMachine internal types.")] internal MemberExpression Build(Type stateType) { Type stateMachineType; diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/ClosureAnalyzer.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/ClosureAnalyzer.cs index a064b4c281..ab9ef42391 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/ClosureAnalyzer.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/ClosureAnalyzer.cs @@ -4,6 +4,7 @@ namespace DotNext.Runtime.CompilerServices; +[RequiresUnreferencedCode("Dynamic access to StrongBox type.")] internal sealed class ClosureAnalyzer : ExpressionVisitor { private static readonly UserDataSlot ClosureVariableSlot = new(); diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs index 809a71ee78..3c8516e8ec 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/InterpolatedStringTemplateBuilder.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -40,6 +41,8 @@ internal Segment(Type argumentType, string? format, int alignment) this.argumentType = argumentType; } + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(BufferWriterSlimInterpolatedStringHandler))] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "DynamicDependencyAttribute is applied")] internal void WriteStatement(IList statements, ParameterExpression provider, ParameterExpression handler, out ParameterExpression? inputVar) { Debug.Assert(provider.Type == typeof(IFormatProvider)); @@ -145,11 +148,19 @@ public void AppendFormatted(Type type, string? format = null) /// the renderer of the interpolated string. /// /// The lambda expression that encapsulates the rendering logic. + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PreallocatedCharBuffer))] + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(BufferWriterSlim))] + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(BufferWriterSlimInterpolatedStringHandler))] + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "DynamicDependencyAttribute is applied")] public readonly LambdaExpression Build() { var preallocatedBufferLocal = Expression.Variable(typeof(PreallocatedCharBuffer), "buffer"); - var writerLocal = Expression.Variable(typeof(BufferWriterSlim), "writer"); - var handlerLocal = Expression.Variable(typeof(BufferWriterSlimInterpolatedStringHandler), "handler"); + + var bufferWriterSlimType = typeof(BufferWriterSlim); + var writerLocal = Expression.Variable(bufferWriterSlimType, "writer"); + + var stringHandlerType = typeof(BufferWriterSlimInterpolatedStringHandler); + var handlerLocal = Expression.Variable(stringHandlerType, "handler"); var providerParameter = Expression.Parameter(typeof(IFormatProvider), "provider"); var allocatorParameter = Expression.Parameter(typeof(MemoryAllocator), "allocator"); @@ -161,7 +172,7 @@ public readonly LambdaExpression Build() var statements = new List(); // instantiate buffer writer - var ctor = writerLocal.Type.GetConstructor([typeof(Span), allocatorParameter.Type]); + var ctor = bufferWriterSlimType.GetConstructor([typeof(Span), allocatorParameter.Type]); Debug.Assert(ctor is not null); Expression expr = Expression.New( ctor, @@ -170,7 +181,7 @@ public readonly LambdaExpression Build() statements.Add(Expression.Assign(writerLocal, expr)); // instantiate handler - ctor = handlerLocal.Type.GetConstructor([typeof(int), typeof(int), writerLocal.Type.MakeByRefType(), providerParameter.Type]); + ctor = stringHandlerType.GetConstructor([typeof(int), typeof(int), writerLocal.Type.MakeByRefType(), providerParameter.Type]); Debug.Assert(ctor is not null); expr = Expression.New( ctor, From af824cea8b7561ffe22950834f7ac012f993ca61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 29 Jan 2024 19:14:12 +0100 Subject: [PATCH 4/5] Add DotNext.Trimming project for trimming analysis. --- src/DotNext.Trimming/DotNext.Trimming.csproj | 34 ++++++++++++++++++++ src/DotNext.Trimming/Program.cs | 1 + src/DotNext.sln | 8 +++++ 3 files changed, 43 insertions(+) create mode 100644 src/DotNext.Trimming/DotNext.Trimming.csproj create mode 100644 src/DotNext.Trimming/Program.cs diff --git a/src/DotNext.Trimming/DotNext.Trimming.csproj b/src/DotNext.Trimming/DotNext.Trimming.csproj new file mode 100644 index 0000000000..a03c12d126 --- /dev/null +++ b/src/DotNext.Trimming/DotNext.Trimming.csproj @@ -0,0 +1,34 @@ + + + + true + latest + enable + Exe + true + true + net8.0 + true + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/DotNext.Trimming/Program.cs b/src/DotNext.Trimming/Program.cs new file mode 100644 index 0000000000..583ceb4ec9 --- /dev/null +++ b/src/DotNext.Trimming/Program.cs @@ -0,0 +1 @@ +return 1; diff --git a/src/DotNext.sln b/src/DotNext.sln index a7ff60b4d3..e0d19b63dc 100644 --- a/src/DotNext.sln +++ b/src/DotNext.sln @@ -40,6 +40,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNext.MaintenanceServices EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLineAMI", "examples\CommandLineAMI\CommandLineAMI.csproj", "{39583DDE-E579-44AD-B7AF-5BB77D979E55}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNext.Trimming", "DotNext.Trimming\DotNext.Trimming.csproj", "{A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Bench|Any CPU = Bench|Any CPU @@ -125,6 +127,12 @@ Global {39583DDE-E579-44AD-B7AF-5BB77D979E55}.Debug|Any CPU.Build.0 = Debug|Any CPU {39583DDE-E579-44AD-B7AF-5BB77D979E55}.Release|Any CPU.ActiveCfg = Release|Any CPU {39583DDE-E579-44AD-B7AF-5BB77D979E55}.Release|Any CPU.Build.0 = Release|Any CPU + {A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}.Bench|Any CPU.ActiveCfg = Debug|Any CPU + {A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}.Bench|Any CPU.Build.0 = Debug|Any CPU + {A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A75C88C1-BAB6-4FEE-B15F-FE06BA79ADB3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 9c731eac23b8b8e0e10b275b1b679f4716aeabe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Tue, 30 Jan 2024 22:33:47 +0100 Subject: [PATCH 5/5] WIP: More trimming annotations in DotNext.Metaprogramming. --- .../Expressions/CollectionAccessExpression.cs | 3 +- .../Linq/Expressions/ForEachExpression.cs | 4 +-- .../Linq/Expressions/MetaExpression.cs | 6 ++-- .../Metaprogramming/AsyncLambdaExpression.cs | 6 ++-- .../Metaprogramming/AwaitForEachStatement.cs | 4 ++- .../Metaprogramming/CodeGenerator.cs | 29 +++++++++++++------ .../Metaprogramming/ForEachStatement.cs | 6 ++-- .../Metaprogramming/LambdaExpression.cs | 5 ++-- .../Metaprogramming/MatchBuilder.cs | 16 +++++++++- .../Runtime/CompilerServices/TaskType.cs | 2 +- 10 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs index 86f4787a3a..e375307d8c 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/CollectionAccessExpression.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; @@ -156,4 +157,4 @@ protected override CollectionAccessExpression VisitChildren(ExpressionVisitor vi var collection = visitor.Visit(Collection); return ReferenceEquals(index, Index) && ReferenceEquals(collection, Collection) ? this : new(collection, index); } -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs index 810a761a2e..9192622213 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/ForEachExpression.cs @@ -14,7 +14,7 @@ namespace DotNext.Linq.Expressions; /// Represents iteration over collection elements as expression. /// /// foreach Statement -[RequiresUnreferencedCode("Dynamic access to GetEnumerator method and IEnumerable interfaces.")] +[RequiresUnreferencedCode("Dynamic access to GetEnumerator (GetAsyncEnumerator) method and IEnumerable (IAsyncEnumerable) interfaces.")] public sealed class ForEachExpression : CustomExpression, ILoopLabels { private const string EnumeratorVarName = "enumerator"; @@ -224,4 +224,4 @@ public override Expression Reduce() return Reduce(moveNextCall, disposeCall); } -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs b/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs index 37b2245a30..cc8a5633b3 100644 --- a/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs +++ b/src/DotNext.Metaprogramming/Linq/Expressions/MetaExpression.cs @@ -1,4 +1,5 @@ -using System.Dynamic; +using System.Diagnostics.CodeAnalysis; +using System.Dynamic; using System.Linq.Expressions; using System.Reflection; using Debug = System.Diagnostics.Debug; @@ -8,6 +9,7 @@ namespace DotNext.Linq.Expressions; using Intrinsics = Runtime.Intrinsics; +[RequiresUnreferencedCode("Binds to arbitrary members.")] internal sealed class MetaExpression : DynamicMetaObject { private static readonly MethodInfo AsExpressionBuilderMethod = new Func?>(Unsafe.As>).Method; @@ -178,4 +180,4 @@ public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder return new MetaExpression(binding, CreateRestrictions().Merge(restrictions)); } -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Metaprogramming/AsyncLambdaExpression.cs b/src/DotNext.Metaprogramming/Metaprogramming/AsyncLambdaExpression.cs index 7c0b3ecc1f..3f6a630252 100644 --- a/src/DotNext.Metaprogramming/Metaprogramming/AsyncLambdaExpression.cs +++ b/src/DotNext.Metaprogramming/Metaprogramming/AsyncLambdaExpression.cs @@ -2,12 +2,14 @@ namespace DotNext.Metaprogramming; +using System.Diagnostics.CodeAnalysis; using Linq.Expressions; using Runtime.CompilerServices; using static Reflection.DelegateType; using List = Collections.Generic.List; -internal sealed class AsyncLambdaExpression : LambdaExpression, ILexicalScope, Action>, ILexicalScope, Action> +[RequiresUnreferencedCode("Dynamic access to Transition and IAsyncStateMachine internal types.")] +internal sealed class AsyncLambdaExpression<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate> : LambdaExpression, ILexicalScope, Action>, ILexicalScope, Action> where TDelegate : Delegate { private readonly bool usePooling; @@ -99,4 +101,4 @@ public override void Dispose() recursion = null; base.Dispose(); } -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Metaprogramming/AwaitForEachStatement.cs b/src/DotNext.Metaprogramming/Metaprogramming/AwaitForEachStatement.cs index 6e62b89194..dbc2303069 100644 --- a/src/DotNext.Metaprogramming/Metaprogramming/AwaitForEachStatement.cs +++ b/src/DotNext.Metaprogramming/Metaprogramming/AwaitForEachStatement.cs @@ -1,9 +1,11 @@ +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; namespace DotNext.Metaprogramming; using ForEachExpression = Linq.Expressions.ForEachExpression; +[RequiresUnreferencedCode("Dynamic access to GetAsyncEnumerator method and IAsyncEnumerable interfaces.")] internal sealed class AwaitForEachStatement : LoopLexicalScope, ILexicalScope>, ILexicalScope> { private readonly Expression collection; @@ -33,4 +35,4 @@ ForEachExpression ILexicalScopeThe method to be called. /// Method call arguments. /// Attempts to call this method out of lexical scope. + [RequiresUnreferencedCode("Dynamically accesses method .")] public static void Call(Expression instance, string methodName, params Expression[] arguments) => Statement(instance.Call(methodName, arguments)); @@ -378,6 +379,7 @@ public static void Call(Expression instance, string methodName, params Expressio /// The method to be called. /// Method call arguments. /// Attempts to call this method out of lexical scope. + [RequiresUnreferencedCode("Dynamically accesses method .")] public static void NullSafeCall(Expression instance, string methodName, params Expression[] arguments) => Statement(instance.IfNotNull(target => target.Call(methodName, arguments))); @@ -406,7 +408,8 @@ public static void CallStatic(MethodInfo method, params Expression[] arguments) /// The name of the static method. /// The arguments to be passed into static method. /// Attempts to call this method out of lexical scope. - public static void CallStatic(Type type, string methodName, params Expression[] arguments) + public static void CallStatic( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type, string methodName, params Expression[] arguments) => Statement(type.CallStatic(methodName, arguments)); /// @@ -416,7 +419,7 @@ public static void CallStatic(Type type, string methodName, params Expression[] /// The name of the static method. /// The arguments to be passed into static method. /// Attempts to call this method out of lexical scope. - public static void CallStatic(string methodName, params Expression[] arguments) + public static void CallStatic<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string methodName, params Expression[] arguments) => CallStatic(typeof(T), methodName, arguments); /// @@ -609,6 +612,7 @@ public static void DoWhile(Expression test, Action body) /// Loop body. /// Attempts to call this method out of lexical scope. /// foreach Statement + [RequiresUnreferencedCode("Dynamic access to GetEnumerator method and IEnumerable interfaces.")] public static void ForEach(Expression collection, Action body) { using var statement = new ForEachStatement(collection); @@ -622,6 +626,7 @@ public static void ForEach(Expression collection, ActionLoop body. /// Attempts to call this method out of lexical scope. /// foreach Statement + [RequiresUnreferencedCode("Dynamic access to GetEnumerator method and IEnumerable interfaces.")] public static void ForEach(Expression collection, Action body) { using var statement = new ForEachStatement(collection); @@ -637,6 +642,7 @@ public static void ForEach(Expression collection, Action body) /// to call with argument when awaiting method. /// Attempts to call this method out of lexical scope. /// Async Streams + [RequiresUnreferencedCode("Dynamic access to GetAsyncEnumerator method and IAsyncEnumerable interfaces.")] public static void AwaitForEach(Expression collection, Action body, Expression? cancellationToken = null, bool configureAwait = false) { using var statement = new AwaitForEachStatement(collection, cancellationToken, configureAwait); @@ -652,6 +658,7 @@ public static void AwaitForEach(Expression collection, Action to call with argument when awaiting method. /// Attempts to call this method out of lexical scope. /// Async Streams + [RequiresUnreferencedCode("Dynamic access to GetAsyncEnumerator method and IAsyncEnumerable interfaces.")] public static void AwaitForEach(Expression collection, Action body, Expression? cancellationToken = null, bool configureAwait = false) { using var statement = new AwaitForEachStatement(collection, cancellationToken, configureAwait); @@ -934,7 +941,7 @@ public static void Return(Expression? result = null) /// if the lambda expression will be compiled with the tail call optimization, otherwise . /// Lambda function builder. /// Constructed lambda expression. - public static Expression Lambda(bool tailCall, Action body) + public static Expression Lambda<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate>(bool tailCall, Action body) where TDelegate : Delegate { using var expression = new LambdaExpression(tailCall); @@ -948,7 +955,7 @@ public static Expression Lambda(bool tailCall, Action if the lambda expression will be compiled with the tail call optimization, otherwise . /// Lambda function builder. /// Constructed lambda expression. - public static Expression Lambda(bool tailCall, Func body) + public static Expression Lambda<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate>(bool tailCall, Func body) where TDelegate : Delegate { using var expression = new LambdaExpression(tailCall); @@ -961,7 +968,7 @@ public static Expression Lambda(bool tailCall, FuncThe delegate describing signature of lambda function. /// Lambda function builder. /// Constructed lambda expression. - public static Expression Lambda(Func body) + public static Expression Lambda<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate>(Func body) where TDelegate : Delegate => Lambda(false, body); @@ -972,7 +979,7 @@ public static Expression Lambda(Func if the lambda expression will be compiled with the tail call optimization, otherwise . /// Lambda function builder. /// Constructed lambda expression. - public static Expression Lambda(bool tailCall, Action body) + public static Expression Lambda<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate>(bool tailCall, Action body) where TDelegate : Delegate { using var expression = new LambdaExpression(tailCall); @@ -985,7 +992,7 @@ public static Expression Lambda(bool tailCall, ActionThe delegate describing signature of lambda function. /// Lambda function builder. /// Constructed lambda expression. - public static Expression Lambda(Action body) + public static Expression Lambda<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate>(Action body) where TDelegate : Delegate => Lambda(false, body); @@ -995,7 +1002,7 @@ public static Expression Lambda(Action body /// The delegate describing signature of lambda function. /// Lambda function builder. /// Constructed lambda expression. - public static Expression Lambda(Action body) + public static Expression Lambda<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate>(Action body) where TDelegate : Delegate => Lambda(false, body); @@ -1008,6 +1015,7 @@ public static Expression Lambda(Action /// /// Async methods + [RequiresUnreferencedCode("Dynamic access to Transition and IAsyncStateMachine internal types.")] public static Expression AsyncLambda(Action body) where TDelegate : Delegate => AsyncLambda(false, body); @@ -1025,6 +1033,7 @@ public static Expression AsyncLambda(Action /// /// /// Async methods + [RequiresUnreferencedCode("Dynamic access to Transition and IAsyncStateMachine internal types.")] public static Expression AsyncLambda(bool usePooling, Action body) where TDelegate : Delegate => new AsyncLambdaExpression(usePooling).Build(body); @@ -1038,6 +1047,7 @@ public static Expression AsyncLambda(bool usePooling, Acti /// /// /// Async methods + [RequiresUnreferencedCode("Dynamic access to Transition and IAsyncStateMachine internal types.")] public static Expression AsyncLambda(Action body) where TDelegate : Delegate => AsyncLambda(false, body); @@ -1055,6 +1065,7 @@ public static Expression AsyncLambda(Action /// /// Async methods + [RequiresUnreferencedCode("Dynamic access to Transition and IAsyncStateMachine internal types.")] public static Expression AsyncLambda(bool usePooling, Action body) where TDelegate : Delegate => new AsyncLambdaExpression(usePooling).Build(body); @@ -1104,4 +1115,4 @@ public static LambdaExpressionTree AsyncLambda(Type[] parameters, Type returnTyp /// The expression to add. public static void Statement(Expression expr) => LexicalScope.Current.AddStatement(expr); -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Metaprogramming/ForEachStatement.cs b/src/DotNext.Metaprogramming/Metaprogramming/ForEachStatement.cs index 856e1657b1..753db4b808 100644 --- a/src/DotNext.Metaprogramming/Metaprogramming/ForEachStatement.cs +++ b/src/DotNext.Metaprogramming/Metaprogramming/ForEachStatement.cs @@ -1,9 +1,11 @@ -using System.Linq.Expressions; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; namespace DotNext.Metaprogramming; using ForEachExpression = Linq.Expressions.ForEachExpression; +[RequiresUnreferencedCode("Dynamic access to GetEnumerator method and IEnumerable interfaces.")] internal sealed class ForEachStatement : LoopLexicalScope, ILexicalScope>, ILexicalScope> { private readonly Expression collection; @@ -26,4 +28,4 @@ ForEachExpression ILexicalScope /// The delegate describing signature of lambda function. -internal sealed class LambdaExpression : LambdaExpression, ILexicalScope, Action>, ILexicalScope, Action>, ILexicalScope, Func> +internal sealed class LambdaExpression<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TDelegate> : LambdaExpression, ILexicalScope, Action>, ILexicalScope, Action>, ILexicalScope, Func> where TDelegate : Delegate { private readonly Type returnType; @@ -148,4 +149,4 @@ public override void Dispose() recursion = null; base.Dispose(); } -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs b/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs index 1ceeabeb65..54959c4149 100644 --- a/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs +++ b/src/DotNext.Metaprogramming/Metaprogramming/MatchBuilder.cs @@ -157,6 +157,7 @@ public MatchBuilder Case(Type expectedType, CaseStatement body) public MatchBuilder Case(CaseStatement body) => Case(typeof(T), body); + [RequiresUnreferencedCode("Dynamically accesses properties/fields named in .")] private static Pattern StructuralPattern(IEnumerable<(string, Expression)> structPattern) => obj => { @@ -170,6 +171,7 @@ private static Pattern StructuralPattern(IEnumerable<(string, Expression)> struc return result ?? Expression.Constant(false); }; + [RequiresUnreferencedCode("Dynamically accesses properties/fields named in .")] private MatchBuilder Case(IEnumerable<(string, Expression)> structPattern, CaseStatement body) => Case(StructuralPattern(structPattern), body); @@ -180,6 +182,7 @@ private MatchBuilder Case(IEnumerable<(string, Expression)> structPattern, CaseS /// The expected value of the field or property. /// The action to be executed if object matches to the pattern. /// this builder. + [RequiresUnreferencedCode("Dynamically accesses property/field .")] public MatchBuilder Case(string memberName, Expression memberValue, Func body) => Case(StructuralPattern(List.Singleton((memberName, memberValue))), value => body(Expression.PropertyOrField(value, memberName))); @@ -192,6 +195,7 @@ public MatchBuilder Case(string memberName, Expression memberValue, FuncThe expected value of the second field or property. /// The action to be executed if object matches to the pattern. /// this builder. + [RequiresUnreferencedCode("Dynamically accesses properties/fields , .")] public MatchBuilder Case(string memberName1, Expression memberValue1, string memberName2, Expression memberValue2, Func body) => Case(StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2)]), value => body(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2))); @@ -206,6 +210,7 @@ public MatchBuilder Case(string memberName1, Expression memberValue1, string mem /// The expected value of the third field or property. /// The action to be executed if object matches to the pattern. /// this builder. + [RequiresUnreferencedCode("Dynamically accesses properties/fields , , .")] public MatchBuilder Case(string memberName1, Expression memberValue1, string memberName2, Expression memberValue2, string memberName3, Expression memberValue3, Func body) => Case(StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2), (memberName3, memberValue3)]), value => body(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2), Expression.PropertyOrField(value, memberName3))); @@ -239,6 +244,7 @@ private static (string, Expression) GetMemberPattern(object @this, string member /// The structure pattern represented by instance of anonymous type. /// The action to be executed if object matches to the pattern. /// this builder. + [RequiresUnreferencedCode("Dynamically accesses properties/fields represented in .")] public MatchBuilder Case(object structPattern, CaseStatement body) => Case(GetProperties(structPattern), body); @@ -248,6 +254,7 @@ public MatchBuilder Case(object structPattern, CaseStatement body) /// The structure pattern represented by instance of anonymous type. /// The value to be supplied if the specified structural pattern matches to the passed object. /// this builder. + [RequiresUnreferencedCode("Dynamically accesses properties/fields represented in .")] public MatchBuilder Case(object structPattern, Expression value) => Case(structPattern, new CaseStatement(value.TrivialCaseStatement)); @@ -313,6 +320,7 @@ public MatchBuilder Case(Pattern pattern, Action body) /// The structure pattern represented by instance of anonymous type. /// The action to be executed if object matches to the pattern. /// this builder. + [RequiresUnreferencedCode("Dynamically accesses fields represented in .")] public MatchBuilder Case(object structPattern, Action body) { using var statement = new MatchByConditionStatement(this, StructuralPattern(GetProperties(structPattern))); @@ -483,6 +491,7 @@ internal CaseStatementBuilder(MatchByMemberStatement statement, string memberNam this.statement = statement; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Public methods on MatchBuilder are annotated appropriately.")] Expression ISupplier.Invoke(ParameterExpression value) { memberHandler(Expression.PropertyOrField(value, memberName)); @@ -500,6 +509,7 @@ internal MatchByMemberStatement(MatchBuilder builder, string memberName, Express this.memberValue = memberValue; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Public methods on MatchBuilder are annotated appropriately.")] private protected override MatchBuilder Build(MatchBuilder builder, Action scope) { var pattern = StructuralPattern(List.Singleton((memberName, memberValue))); @@ -524,6 +534,7 @@ internal CaseStatementBuilder(MatchByTwoMembersStatement statement, string membe this.statement = statement; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Public methods on MatchBuilder are annotated appropriately.")] Expression ISupplier.Invoke(ParameterExpression value) { memberHandler(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2)); @@ -543,6 +554,7 @@ internal MatchByTwoMembersStatement(MatchBuilder builder, string memberName1, Ex this.memberValue2 = memberValue2; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Public methods on MatchBuilder are annotated appropriately.")] private protected override MatchBuilder Build(MatchBuilder builder, Action scope) { var pattern = StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2)]); @@ -568,6 +580,7 @@ internal CaseStatementBuilder(MatchByThreeMembersStatement statement, string mem this.statement = statement; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Public methods on MatchBuilder are annotated appropriately.")] Expression ISupplier.Invoke(ParameterExpression value) { memberHandler(Expression.PropertyOrField(value, memberName1), Expression.PropertyOrField(value, memberName2), Expression.PropertyOrField(value, memberName3)); @@ -589,6 +602,7 @@ internal MatchByThreeMembersStatement(MatchBuilder builder, string memberName1, this.memberValue3 = memberValue3; } + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Public methods on MatchBuilder are annotated appropriately.")] private protected override MatchBuilder Build(MatchBuilder builder, Action scope) { var pattern = StructuralPattern([(memberName1, memberValue1), (memberName2, memberValue2), (memberName3, memberValue3)]); @@ -635,4 +649,4 @@ file static class ExpressionHelpers [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1313", Justification = "Underscore is used to indicate that the parameter is unused")] internal static Expression TrivialCaseStatement(this Expression value, ParameterExpression _) => value; -} \ No newline at end of file +} diff --git a/src/DotNext.Metaprogramming/Runtime/CompilerServices/TaskType.cs b/src/DotNext.Metaprogramming/Runtime/CompilerServices/TaskType.cs index da11274d4f..64cf00ed8d 100644 --- a/src/DotNext.Metaprogramming/Runtime/CompilerServices/TaskType.cs +++ b/src/DotNext.Metaprogramming/Runtime/CompilerServices/TaskType.cs @@ -54,4 +54,4 @@ internal MethodCallExpression AdjustTaskType(MethodCallExpression startMachineCa internal bool IsValueTask => taskType is { IsValueType: true }; public static implicit operator Type(in TaskType type) => type.taskType ?? typeof(Task); -} \ No newline at end of file +}