diff --git a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs index c04f806482679..6ea90acdd4ec4 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs @@ -13757,7 +13757,7 @@ void M2() } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/71926")] - public async Task NecessaryDelegateCast() + public async Task NecessaryDelegateCast1() { await new VerifyCS.Test { @@ -13778,4 +13778,34 @@ static void Main(string[] args) ReferenceAssemblies = ReferenceAssemblies.Net.Net80, }.RunAsync(); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72134")] + public async Task NecessaryDelegateCast2() + { + await new VerifyCS.Test + { + TestCode = """ + using System; + + public class MyClass + { + static void Main() + { + Goo f = (Action)(() => { }); // IDE0004: Cast is redundant. + + } + } + + public class Goo + { + public static implicit operator Goo(Action value) + { + return default!; + } + } + """, + LanguageVersion = LanguageVersion.CSharp12, + ReferenceAssemblies = ReferenceAssemblies.Net.Net80, + }.RunAsync(); + } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs index c7f04caee0265..ae4d58e83e4bb 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs @@ -327,6 +327,14 @@ private static bool IsConversionCastSafeToRemove( if (isNullLiteralCast && !originalConvertedType.IsReferenceType && !originalConvertedType.IsNullable()) return false; + // SomeType s = (Action)(() => {}); // Where there's a user defined conversion from Action->SomeType. + // + // This cast is necessary. The language does not allow lambdas to be directly converted to the destination + // type without explicitly stating the intermediary reified delegate type. + var isAnonymousFunctionCast = castedExpressionNode.WalkDownParentheses() is AnonymousFunctionExpressionSyntax; + if (isAnonymousFunctionCast && originalConversion.IsUserDefined) + return false; + // So far, this looks potentially possible to remove. Now, actually do the removal and get the // semantic model for the rewritten code so we can check it to make sure semantics were preserved. var (rewrittenSemanticModel, rewrittenExpression) = GetSemanticModelWithCastRemoved(