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

Collection expressions: require applicable constructor and Add method for target type implementing IEnumerable #71592

Merged
merged 20 commits into from
Jan 26, 2024

Conversation

cston
Copy link
Member

@cston cston commented Jan 11, 2024

See corresponding spec changes dotnet/csharplang#7802 and dotnet/csharplang#7873.

Relates to test plan #66418

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Jan 11, 2024
@cston
Copy link
Member Author

cston commented Jan 12, 2024

                public void Add(ref readonly T t) { _list.Add(t); }

Is it expected that an Add(ref readonly T t) method can be used implicitly for collection initializers or collection expressions?


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:6417 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@cston
Copy link
Member Author

cston commented Jan 12, 2024

            Diagnostic(ErrorCode.ERR_BadArgTypesForCollectionAdd, "[(IA)null, (IB)null, new AB()]").WithArguments("C.Add(IA)").WithLocation(15, 15),

We should consider reporting a specific error for collection expressions: "no applicable Add method that can be called with argument of type 'T'". #Resolved


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:5802 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@@ -183,6 +182,19 @@ protected override Conversion GetInterpolatedStringConversion(BoundExpression so

Debug.Assert(elementType is { });

if (collectionTypeKind == CollectionExpressionTypeKind.ImplementsIEnumerable)
Copy link
Member Author

@cston cston Jan 12, 2024

Choose a reason for hiding this comment

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

if

Need to update breaking change document with the additional conversion requirements: an accessible .ctor callable with no arguments, and an accessible Add method callable with an argument of the iteration type.

For instance, Dictionary<string, object> d = []; is no longer supported, and collection expressions cannot be converted to string. #Resolved

@cston
Copy link
Member Author

cston commented Jan 12, 2024

    public void ListBase()

Removed test since the diagnostics have changed (ListBase<T> does not have the required Add(T) method), and it's not clear what this is testing other than the required `Add(T) method. #Resolved


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:3756 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = True)

@cston cston marked this pull request as ready for review January 12, 2024 07:59
@cston cston requested review from a team as code owners January 12, 2024 07:59
{
if (!HasCollectionExpressionApplicableConstructor(node.Syntax, targetType, diagnostics))
{
reportedErrors = true;
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 12, 2024

Choose a reason for hiding this comment

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

reportedErrors = true;

Are we assuming a general error "No conversion" has been reported elsewhere? #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

If so, consider adding a comment pointing to the code doing that


if (!HasCollectionExpressionApplicableAddMethod(node.Syntax, targetType, elementType, diagnostics))
{
reportedErrors = true;
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 12, 2024

Choose a reason for hiding this comment

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

reportedErrors = true;

It looks like we end up here for ListInterfaces_01 unit-test and report errors that HasCollectionExpressionApplicableAddMethod reports. I think that the errors look confusing. Consider dropping the diagnostics and reporting a dedicated error instead. Something like "conversion from collection expression to type '{targetType}' doesn't exist because there is no accessible method that accepts value of type'{elementType}'" #Closed

Copy link
Contributor

Choose a reason for hiding this comment

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

Dependencies can be dropped too, since we are reporting an error. Accurate tracking of dependencies is not supported for error scenarios

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we can report "error CS1061: '{targetType}' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)" when HasCollectionExpressionApplicableAddMethod doesn't report that itself.

Copy link
Contributor

Choose a reason for hiding this comment

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

It is quite possible that we only need to worry when HasCollectionExpressionApplicableAddMethod reports "error CS1950: The best overloaded Add method '{bestCandidate}' for the collection initializer has some invalid arguments"

{
if (!HasCollectionExpressionApplicableConstructor(node.Syntax, targetType, diagnostics))
{
reportedErrors = true;
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 12, 2024

Choose a reason for hiding this comment

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

reportedErrors = true;

Similar suggestion about reporting dedicated error instead. #Closed

Copy link
Contributor

@AlekseyTs AlekseyTs Jan 12, 2024

Choose a reason for hiding this comment

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

On the other hand, if "error CS1729: '{targetType}' does not contain a constructor that takes 0 arguments" and the like are the only errors that we can get from HasCollectionExpressionApplicableConstructor, that is probably fine too.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jan 12, 2024

            // (12,13): error CS7036: There is no argument given that corresponds to the required parameter 'y' of 'S<int>.Add(int, int)'

This error also feels confusing #Closed


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:5830 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jan 12, 2024

            // (13,42): error CS1954: The best overloaded method match 'MyCollection<object>.Add(out object)' for the collection initializer element cannot be used. Collection initializer 'Add' methods cannot have ref or out parameters.

This one is probably confusing too #Closed


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:6334 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

                public void Add(ref readonly T t) { _list.Add(t); }

Is it expected that an Add(ref readonly T t) method can be used implicitly for collection initializers or collection expressions?

Can one call it explicitly without a modifier?


In reply to: 1888571804


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:6417 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

                public void Add(ref readonly T t) { _list.Add(t); }

It looks like it is working for collection initializers, perhaps we should go along


In reply to: 1889982854


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:6417 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

{
if (!HasCollectionExpressionApplicableConstructor(node.Syntax, targetType, diagnostics))
{
reportedErrors = true;
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 12, 2024

Choose a reason for hiding this comment

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

reportedErrors = true;

Are we covering this code path for a type parameter? #Closed

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, there are several tests that hit this with a type parameter, including TypeParameter_03.

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jan 12, 2024

            // 0.cs(11,13): error CS0012: The type 'A2' is defined in an assembly that is not referenced. You must add a reference to assembly 'a897d975-a839-4fff-828b-deccf9495adc, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

It feels like this information is useful for a user #Closed


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:7496 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jan 12, 2024

            // (4,7): error CS7036: There is no argument given that corresponds to the required parameter 's' of 'C.C(string)'

This is probably confusing #Closed


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:24829 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jan 12, 2024

            // (6,90): error CS0304: Cannot create an instance of the variable type 'T1' because it does not have the new() constraint

This is probably confusing too #Closed


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:25282 in 1ad210c. [](commit_id = 1ad210c, deletion_comment = False)

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 3). I think the error reporting should be improved. At the moment, I am not sure about the implementation strategy for that. It is quite possible that the most reliable way is to have overload resolution report errors in a special mode for the two interesting call sites. Basically never report specific confusing errors and report other errors instead.

@jaredpar jaredpar added this to the 17.10 milestone Jan 17, 2024
@cston
Copy link
Member Author

cston commented Jan 18, 2024

            // 1.cs(6,23): error CS1503: Argument 1: cannot convert from 'object' to 'int'

Consider adjusting the error message to clarify that object is the iteration type

Thanks. I'll consider potentially for a subsequent change. Presumably, it would require checking for BinderFlags.CollectionExpressionConversionValidation in OverloadResolutionResult.ReportBadArgumentError().


In reply to: 1899196694


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:3783 in 559c4fc. [](commit_id = 559c4fc, deletion_comment = False)

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 13)

@jcouv
Copy link
Member

jcouv commented Jan 23, 2024

            // 1.cs(6,23): error CS1503: Argument 1: cannot convert from 'object' to 'int'

Sorry, I realize it wouldn't help here, but I was proposing to modify the error message you're adding:
"Collection expression type must have an applicable instance or extension method 'Add' that can be called with an argument of iteration type '{0}'"


In reply to: 1899232311


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:3783 in 559c4fc. [](commit_id = 559c4fc, deletion_comment = False)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 13)

AlekseyTs
AlekseyTs previously approved these changes Jan 25, 2024
Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 15), I assume more changes are coming to this PR

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 15)

@AlekseyTs
Copy link
Contributor

@cston It looks like there are legitimate test failures


internal bool HasCollectionExpressionApplicableAddMethod(SyntaxNode syntax, TypeSymbol targetType, TypeSymbol elementType, ImmutableArray<BoundNode> elements, BindingDiagnosticBag diagnostics)
{
if (elements.Length == 0)
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 25, 2024

Choose a reason for hiding this comment

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

if (elements.Length == 0)

Consider adjusting the two call sites instead. For example, the check for an Add method will be applicable to params parameters, but there won't be any list of Items to pass and to have to fake them feels like an overkill. #Closed

@AlekseyTs
Copy link
Contributor

AlekseyTs commented Jan 25, 2024

Do we have any success test case for an empty collection expression without an Add method? #Closed


Refers to: src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs:32927 in 7bb2741. [](commit_id = 7bb2741, deletion_comment = False)

@AlekseyTs AlekseyTs dismissed their stale review January 26, 2024 00:01

Done with review pass (commit 18)

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 19)

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM (commit 20)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 20)

@cston cston merged commit cd90f6f into dotnet:main Jan 26, 2024
31 checks passed
@cston cston deleted the check-add branch January 26, 2024 18:36
@ghost ghost modified the milestones: 17.10, Next Jan 26, 2024
@Cosifne Cosifne modified the milestones: Next, 17.10 P1 Jan 30, 2024
halter73 added a commit to dotnet/aspnetcore that referenced this pull request Feb 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers New Feature - Collection Expressions untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants