Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hande error scenarios involving target types and named arguments in nullable walker #72635

Merged
merged 4 commits into from
Mar 25, 2024
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
13 changes: 8 additions & 5 deletions src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6718,7 +6718,13 @@ private ImmutableArray<VisitResult> VisitArguments(
(ParameterSymbol? parameter, TypeWithAnnotations parameterType, FlowAnalysisAnnotations parameterAnnotations, bool isExpandedParamsArgument) =
GetCorrespondingParameter(i, parametersOpt, argsToParamsOpt, expanded, ref paramsIterationType);

if (parameter is null)
if (// This is known to happen for certain error scenarios, because
// the parameter matching logic above is not as flexible as the one we use in `Binder.BuildArgumentsForErrorRecovery`
// so we may end up with a pending conversion completion for an argument apparently without a corresponding parameter.
parameter is null ||
// In error recovery with named arguments, target-typing cannot work as we can get a different parameter type
// from our GetCorrespondingParameter logic than Binder.BuildArgumentsForErrorRecovery does.
node is BoundCall { HasErrors: true, ArgumentNamesOpt.IsDefaultOrEmpty: false, ArgsToParamsOpt.IsDefault: true })
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you explain why we want ArgsToParamsOpt to be default in order to enter this path?

Copy link
Member Author

Choose a reason for hiding this comment

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

If it's not default it means we know the args-to-params mapping so we can continue. The problem is only in error scenarios where the bad BoundCall does not contain the mapping even though there are named arguments in the call. That's when we want to enter this path to skip further processing.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to merge before the snap. Will follow up if you have more comments. Thanks.

{
if (IsTargetTypedExpression(argumentNoConversion) && _targetTypedAnalysisCompletionOpt?.TryGetValue(argumentNoConversion, out var completion) is true)
{
Expand All @@ -6728,10 +6734,7 @@ private ImmutableArray<VisitResult> VisitArguments(
completion(TypeWithAnnotations.Create(argument.Type));
TargetTypedAnalysisCompletion.Remove(argumentNoConversion);

// This is known to happen for certain error scenarios, because
// the parameter matching logic above is not as flexible as the one we use in `Binder.BuildArgumentsForErrorRecovery`
// so we may end up with a pending conversion completion for an argument apparently without a corresponding parameter.
Debug.Assert(method is ErrorMethodSymbol);
Debug.Assert(parameter is not null || method is ErrorMethodSymbol);
}
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13431,6 +13431,56 @@ private static void VerifyTypes(SemanticModel model, ExpressionSyntax expr, stri
Assert.Equal(expectedConversionKind, conversion.Kind);
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72541")]
public void NamedArgumentConversion()
{
var source = """
#nullable enable
using System.Collections.Generic;

static class C
{
static void Main()
{
C.M(y: [new D { }]);
}
static void M(string x, IReadOnlyList<D> y) { }
}

class D { }
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,11): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'C.M(string, IReadOnlyList<D>)'
// C.M(y: [new D { }]);
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("x", "C.M(string, System.Collections.Generic.IReadOnlyList<D>)").WithLocation(8, 11));
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72541")]
public void NamedArgumentConversion_CollectionInitializer()
{
var source = """
#nullable enable
using System.Collections.Generic;

static class C
{
static void Main()
{
C.M(y: new() { new D() { } });
}
static void M(string x, List<D> y) { }
}

class D { }
""";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (8,11): error CS7036: There is no argument given that corresponds to the required parameter 'x' of 'C.M(string, List<D>)'
// C.M(y: new() { new D() { } });
Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "M").WithArguments("x", "C.M(string, System.Collections.Generic.List<D>)").WithLocation(8, 11));
}

[CombinatorialData]
[Theory]
public void CollectionBuilder_01(bool useCompilationReference)
Expand Down
Loading