dotnet / dotnet/roslyn

Collection expressions are suggested for types where it doesn't make sense, and their error messages show inconsistent types

Open
#73,655 38 comments 1 reaction 0 assignees View on GitHub
Area-Compilers Concept-Diagnostic Clarity Feature - Collection Expressions
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

**Version Used**:
- First noticed in VS 17.9.6 with SDK 8.0.204
- Last tested in VS 18.6.1 with SDK 10.0.300 (Compiler version: '5.6.0-2.26230.15 (a0ccfc09f8af4a6d4756397fa89c65efd95f70a6)'. Language version: 14.0)

**Steps to Reproduce**:
See comments in the sample:
```cs
using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleApp1;

internal class Program
{
private readonly InlineValidator _validator;

public Program()
{
// This shows "IDE0028 Collection initialization can be simplified", but only if the Add method below exists.
// Should it really show this message? I think using a collection expression here is very weird.
_validator = new InlineValidator();

// Applying the code fix results in the following working, but weird, code.
// This still compiles if the Add method below does not exist.
_validator = [];

// This calls the Add method below, but should it?
// The type of the parameter is something completely different than the type of the IEnumerable element.
// If the Add method below does not exist, then this shows error "CS1061 'InlineValidator' does not
// contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type
// 'InlineValidator' could be found".
// This makes even less sense. Why does it try to find an Add method with parameter type
// InlineValidator? Shouldn't it only be parameter type DateTime or IValidationRule (depending on
// whether it should be the generic type of the class itself, or the IEnumerable type)?
_validator = [null!];

// This shows error "CS0029 Cannot implicitly convert type 'int' to 'ConsoleApp1.IValidationRule'.
// This is different from the line above (when the Add method exists). There the compiler passed null as the
// Add method parameter type (Func). But now it tries to convert it to the IEnumerable element type? Why?
//_validator = [1];
}
}

public class InlineValidator : IEnumerable
{
public void Add(Func someFunc)
{
someFunc(1);
}

public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}

public interface IValidationRule;
```
[Sample in SharpLab](https://sharplab.io/#v2:D4AQTAjAsAUCAMACEEB0BhA9gG2wUwGMAXAS0wDsBnAblgWQgBZaZZyBDAWz0oAd2CeRFio48AQV68ILWCXJE8AJw7ZkYBgHZYAb1iIDiXkpIA3dosRK87ACYVsAT0QBJctnl4Aauw+2LmEoAPAAiFngAKiTcAHyIAPrmfgFKsjCGyADMWgAUAJT6hnrpGYYA9GWIEQAWJJSIlNWYAO71AEQuIQCi8PBgABzCOPjEZOSI8iSkviQAXhZjiATs4wBGQpTRvB4AZiR4tm0ANIirAK5EiA7OJDuIRNVC4ra2iNwPmK/r2C2IeAAedSIlFQhVKiAqiAAyk0zthXlMrDZcM5Gr8HnU3jxKOwAOZ4AD8rnutXIAGtkEh2EthoRSBQ/v9jNjFo9rBN6qZlM5mngSEpbKCSuDEjN/ERAogALyIch4ZqudyeHzJCXBMKKKKxfJpcEGSGSbaOeS4klCAifIR7f5Iyhw4ETcYPK3DFomxDNQJkk0nc6XXn82wnC22PBCvUQyo1TGUUi4GmcXgkfD1W5mxDPV7vJpfPA/BX2HiyzCXAFA8N60WqyUygDaAF1dXrIdH6stcPVnRmXliPrn876Lg1YfCJkQCWDSi3HvdHLwhJg7l3+EouHhFEoOQ1MNn3RbE/hFE5ELZbjtlHgFCSVumiHOF0uZyhsnm8NwFBXwZCXI+nj3s58px5r8hb1OQJaMkCJzOk6tT1GirR/EoSiSm06BQhA8AAGwQIgADkbgeHKKokOKgShOEWp4DEeEnpgRbgUQk4ZJCFoKOw8iINSoZ7OQUyLDskp4ZmtErK84FcQQgiUJsqz4IyihUIsAGvMJLyiVJeC8KQ5CmtSexKLGXFKLiZzvpci6zvOzHlJUBFKsRYopBRmrRNRtEWnCuaIIJZzkIcn5TlGcFvOwZJFngXLjCm8GXpQYaIAA6tUzigWO9xKM4Eo+fIrw3pmvY5h6UzVEY7Cru8yhWXgNn6pUhHKk5aouZEbkxESMKYF55B4ZciLXEBZUVeuVV3vOiAaq13BXJuLgkeKYwAEpwkIOShvO/nuhQtWRh6jzOpuiJol5g1dvicomAQ1VXL+6hjvF2A7Cckpds+1V5BOwqlFWpEpNKiC1uQcLYAAhI2sA7dOMZNIhygoZuaFQr0YAAJzCCsjETAeJAEFMx5sVySiXGNQh4fIRC0dleEiJQYiGmgc1NUtK14YFLHBZimKnjs57WFeOwoZw6ZEUI7CrJgXKIDkzSPLBf5ZuuRVlrGlB5KgVRskIXb7km+CbvwMkHLKwNcZ2jyQ5UBUqUNa4btdOQgAArGriAAEJDuBCqIkQJhFtlBPKH1xOYOmb2vuZ1VEsljifRGFQ/WRm51hA4NfQAvrAGesHA2TgIqIvzc5ERxAAXAwmRBIzqrM/gMS6JOIC54w3a2A7jtBOTvqYDgcS09wTsFF9xQRn3eBOzkEB5CwGRZw32QuF0QPcKuzVV799LkMtteIAA4uui9mcoKT5JOw96g8KEKnKCoAHIli4B5vpeii2F0/yCNpYw6pOWcZAvS9HzVOXVAe8iAH2XsfQeGQz7ggvr8a+iA75EAftsJ+CgDhvw/hvb+6dM4Qxzo6DcOwBBCDXgtCgW88AsCAA===)

My actual project uses https://github.com/FluentValidation/FluentValidation. The sample contains simplified versions of the FluentValidation classes.

**Diagnostic Id**:
Initially `"IDE0028: Collection initialization can be simplified"`.
But the following error messages are shown if you modify the sample as explained in the comments:
- `"CS1061: 'InlineValidator' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'InlineValidator' could be found"`
- `"CS0029: Cannot implicitly convert type 'int' to 'ConsoleApp1.IValidationRule"`

**Expected Behavior**:
I don't expect to see `"IDE0028: Collection initialization can be simplified"` for `new InlineValidator()`. I think this should only be shown if the parameter type of the `Add` method matches the collection type.
I expect consistant parameter/element types shown in the error messages if you modify the sample as explained in the comments.

**Actual Behavior**:
See comments in the sample code.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the C# sample in the issue, using SharpLab or the reported IDE0028 scenario, and compare the diagnostics for the empty and non-empty collection expressions. Investigate the collection-expression suggestion and the CS1061/CS0029 type reporting; done means the suggestion is suppressed when inappropriate and the resulting diagnostics consistently report the relevant parameter or element type.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.