From 60be1e4b19e9849deaaae06460844f3b8ce46123 Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Tue, 7 Sep 2021 17:30:27 -0700 Subject: [PATCH 1/2] Infer delegate type from lambda expression with explicit return statements --- .../Portable/BoundTree/UnboundLambda.cs | 2 +- .../Semantic/Semantics/DelegateTypeTests.cs | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index e3c1f8e58c278..41ffb837cc4f2 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -624,7 +624,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo returnType = inferredReturnType.TypeWithAnnotations; returnRefKind = inferredReturnType.RefKind; - if (!returnType.HasType && returnTypes.Count > 0) + if (!returnType.HasType && inferredReturnType.NumExpressions > 0) { return null; } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 7edef10a37d1e..abff5e3a82a2a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -3804,6 +3804,51 @@ static void Main() Assert.True(HaveMatchingSignatures(((INamedTypeSymbol)typeInfo.Type!).DelegateInvokeMethod!, method)); } + [WorkItem(55320, "https://github.com/dotnet/roslyn/issues/55320")] + [Fact] + public void InferredReturnType_01() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(() => { return; }); + Report((bool b) => { if (b) return; }); + Report((bool b) => { if (b) return; else return; }); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: +@"System.Action +System.Action`1[System.Boolean] +System.Action`1[System.Boolean] +"); + } + + [Fact] + public void InferredReturnType_02() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(async () => { return; }); + Report(async (bool b) => { if (b) return; }); + Report(async (bool b) => { if (b) return; else return; }); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: +@"System.Func`1[System.Threading.Tasks.Task] +System.Func`2[System.Boolean,System.Threading.Tasks.Task] +System.Func`2[System.Boolean,System.Threading.Tasks.Task] +"); + } + [Fact] public void TypeInference_Constraints_01() { From fc15739490b4850e23d6e62ed1ca5dc574d43dfa Mon Sep 17 00:00:00 2001 From: Charles Stoner Date: Mon, 13 Sep 2021 14:02:10 -0700 Subject: [PATCH 2/2] More tests --- .../Semantic/Semantics/DelegateTypeTests.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index abff5e3a82a2a..85315cb712b72 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -3849,6 +3849,90 @@ static void Main() "); } + [WorkItem(55320, "https://github.com/dotnet/roslyn/issues/55320")] + [Fact] + public void InferredReturnType_03() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report((bool b) => { if (b) return null; }); + Report((bool b) => { if (b) return; else return null; }); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (6,16): error CS8917: The delegate type could not be inferred. + // Report((bool b) => { if (b) return null; }); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(bool b) => { if (b) return null; }").WithLocation(6, 16), + // (7,16): error CS8917: The delegate type could not be inferred. + // Report((bool b) => { if (b) return; else return null; }); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(bool b) => { if (b) return; else return null; }").WithLocation(7, 16), + // (7,50): error CS8030: Anonymous function converted to a void returning delegate cannot return a value + // Report((bool b) => { if (b) return; else return null; }); + Diagnostic(ErrorCode.ERR_RetNoObjectRequiredLambda, "return").WithLocation(7, 50)); + } + + [WorkItem(55320, "https://github.com/dotnet/roslyn/issues/55320")] + [Fact] + public void InferredReturnType_04() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report((bool b) => { if (b) return default; }); + Report((bool b) => { if (b) return; else return default; }); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (6,16): error CS8917: The delegate type could not be inferred. + // Report((bool b) => { if (b) return default; }); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(bool b) => { if (b) return default; }").WithLocation(6, 16), + // (7,16): error CS8917: The delegate type could not be inferred. + // Report((bool b) => { if (b) return; else return default; }); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "(bool b) => { if (b) return; else return default; }").WithLocation(7, 16), + // (7,50): error CS8030: Anonymous function converted to a void returning delegate cannot return a value + // Report((bool b) => { if (b) return; else return default; }); + Diagnostic(ErrorCode.ERR_RetNoObjectRequiredLambda, "return").WithLocation(7, 50)); + } + + [Fact] + public void ExplicitReturnType_01() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Report(object () => { return; }); + Report(object (bool b) => { if (b) return null; }); + Report(object (bool b) => { if (b) return; else return default; }); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (6,31): error CS0126: An object of a type convertible to 'object' is required + // Report(object () => { return; }); + Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("object").WithLocation(6, 31), + // (7,32): error CS1643: Not all code paths return a value in lambda expression of type 'Func' + // Report(object (bool b) => { if (b) return null; }); + Diagnostic(ErrorCode.ERR_AnonymousReturnExpected, "=>").WithArguments("lambda expression", "System.Func").WithLocation(7, 32), + // (8,44): error CS0126: An object of a type convertible to 'object' is required + // Report(object (bool b) => { if (b) return; else return default; }); + Diagnostic(ErrorCode.ERR_RetObjectRequired, "return").WithArguments("object").WithLocation(8, 44)); + } + [Fact] public void TypeInference_Constraints_01() {