docs/compilers/CSharp/Compiler Breaking Changes - VS2019.md
This document lists known breaking changes in Roslyn 3.0 (Visual Studio 2019) from Roslyn 2.* (Visual Studio 2017)
Breaks are formatted with a monotonically increasing numbered list to allow them to referenced via shorthand (i.e., "known break #1"). Each entry should include a short description of the break, followed by either a link to the issue describing the full details of the break or the full details of the break inline.
https://github.com/dotnet/roslyn/issues/27800 C# will now preserve left-to-right evaluation for compound assignment addition/subtraction expressions where the left-hand side is dynamic. In this example code:
class DynamicTest
{
public int Property { get; set; }
static dynamic GetDynamic() => return new DynamicTest();
static int GetInt() => 1;
public static void Main() => GetDynamic().Property += GetInt();
}
Previous versions of Roslyn would have evaluated this as:
We now evaluate it as:
Previously, we allowed adding a module with Microsoft.CodeAnalysis.EmbeddedAttribute or System.Runtime.CompilerServices.NonNullTypesAttribute types declared in it.
In Visual Studio 2019, this produces a collision error with the injected declarations of those types.
Previously, you could refer to a System.Runtime.CompilerServices.NonNullTypesAttribute type declared in a referenced assembly.
In Visual Studio 2019, the type from assembly is ignored in favor of the injected declaration of that type.
https://github.com/dotnet/roslyn/issues/29656 Previously, ref-returning async local functions would compile, by ignoring the ref modifier of the return type.
In Visual Studio 2019, this now produces an error, just like ref-returning async methods do.
https://github.com/dotnet/roslyn/issues/27748 C# will now produce a warning for an expression of the form e is _. The is_type_expression can be used with a type named _. However, in C# 8 we are introducing a discard pattern written _ (which cannot be used as the pattern of an is_pattern_expression). To reduce confusion, there is a new warning when you write e is _:
(11,31): warning CS8413: The name '_' refers to the type 'Program1._', not the discard pattern. Use '@_' for the type, or 'var _' to discard.
bool M1(object o) => o is _;
C# 8 produces a warning when a switch statement uses a constant named _ as a case label.
(1,18): warning CS8512: The name '_' refers to the constant '_', not the discard pattern. Use 'var _' to discard the value, or '@_' to refer to a constant by that name.
switch(e) { case _: break; }
In C# 8.0, the parentheses of a switch statement are optional when the expression being switched on is a tuple expression, because the tuple expression has its own parentheses:
switch (a, b)
Due to this the OpenParenToken and CloseParenToken fields of a SwitchStatementSyntax node may now sometimes be empty.
In an is-pattern-expression, a warning is now issued when a constant expression does not match the provided pattern because of its value. Such code was previously accepted but gave no warning. For example:
if (3 is 4) // warning: the given expression never matches the provided pattern.
We also issue a warning when a constant expression always matches a constant pattern in an is-pattern-expression. For example
if (3 is 3) // warning: the given expression always matches the provided constant.
Other cases of the pattern always matching (e.g. e is var t) do not trigger a warning, even when they are known by the compiler to produce an invariant result.
https://github.com/dotnet/roslyn/issues/26098 In C# 8, we give a warning when an is-type expression is always false because the input type is an open class type and the type it is tested against is a value type:
class C<T> { }
void M<T>(C<T> x)
{
if (x is int) { } // warning: the given expression is never of the provided ('int') type.
}
previously, we gave the warning only in the reverse case
void M<T>(int x)
{
if (x is C<T>) { } // warning: the given expression is never of the provided ('C<T>') type.
}
Previously, reference assemblies were emitted including embedded resources. In Visual Studio 2019, embedded resources are no longer emitted into ref assemblies. See https://github.com/dotnet/roslyn/issues/31197
Ref structs now support disposal via pattern. A ref struct enumerator with an accessible void Dispose() instance method will now have it invoked at the end of enumeration, regardless of whether the struct type implements IDisposable:
public class C
{
public ref struct RefEnumerator
{
public int Current => 0;
public bool MoveNext() => false;
public void Dispose() => Console.WriteLine("Called in C# 8.0 only");
}
public RefEnumerator GetEnumerator() => new RefEnumerator();
public static void Main()
{
foreach(var x in new C())
{
}
// RefEnumerator.Dispose() will be called here in C# 8.0
}
}
https://github.com/dotnet/roslyn/issues/32732 Switch statements that handle both a true case and a false case are now considered to handle all of the possible input values.