Roslyn's general philosophy on LangVersion checks is that they shouldn't affect how binding is performed. However, there exists a place that they can affect binding today: when we test to see whether or not a lambda can be converted to a delegate type. Consider this example:
using System;
namespace test
{
public class Class1
{
void M(Action<(int, int)> param) { }
void M(Action<int> param) { }
void M1()
{
M(param => _ = param == param);
}
}
}
With today's compiler, if you compile that sample with LangVersion set to 7.2 or earlier, it succeeds. Compile it with 7.3 or later, and compilation fails because the call to M is considered ambiguous. This happens because using the == operator to compare tuples wasn't added until C# 7.3, so when compiling with 7.2 we create a diagnostic about the language version for M(Action<(int, int)> param). Later, when considering whether the lambda bound to the delegate type successfully, we look through the errors reported to see whether any of them should prevent conversion: this allow list is maintained here. LangVersion is not in the list, so the conversion is considered unsuccessful and M(Action<(int, int)> param) is removed from the candidate list, leaving only one overload.
There's a few paths forward here:
In the short term, we can look at this list of errors and either add new errors to it, or invert it to be a deny list. However, it has been a long time since this list was updated (nearly a full decade ago) and many, many errors have been added since then. It will take a good deal of manual work to try and update this list manually. It is also a breaking change: we can at least add langversion-related errors and do some smoke tests to see if this meaningfully affects current code.
In the longer-term, this list is fragile and requires a good deal of manual work. We should investigate if there are other ways to prevent the issues this was originally added to prevent, to avoid having to try and keep this list updated.
Comment from Aleksey on a short-term suggestion to the allow-list code:
Adjusting the code so that it can intercept all current and future language version errors. I think they are already specially recognizable, since the required language version is supplied in a special way for IDE to recognize.
Adding a dedicated method in this class that returns true for a language version error and using that helper here. Adding relevant comments and asserts in some strategic places to guide devs into the direction of this new helper.
Roslyn's general philosophy on LangVersion checks is that they shouldn't affect how binding is performed. However, there exists a place that they can affect binding today: when we test to see whether or not a lambda can be converted to a delegate type. Consider this example:
With today's compiler, if you compile that sample with LangVersion set to 7.2 or earlier, it succeeds. Compile it with 7.3 or later, and compilation fails because the call to
M
is considered ambiguous. This happens because using the==
operator to compare tuples wasn't added until C# 7.3, so when compiling with 7.2 we create a diagnostic about the language version forM(Action<(int, int)> param)
. Later, when considering whether the lambda bound to the delegate type successfully, we look through the errors reported to see whether any of them should prevent conversion: this allow list is maintained here. LangVersion is not in the list, so the conversion is considered unsuccessful andM(Action<(int, int)> param)
is removed from the candidate list, leaving only one overload.There's a few paths forward here: