Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WalkDownParentheses

assume it's not expensive to call as it was called a couple lines above too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be nearly free. It's normally a no-op, or occasionally a walk of one node.

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(
Expand Down