From 3f19fb533ff512df8f38c7825bc6378aa55ae83d Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 14 Apr 2017 14:11:51 -0700 Subject: [PATCH] More tests and suggestions on default literal (#18604) --- .../Portable/Binder/Binder_Operators.cs | 2 +- .../Portable/Binder/ForEachLoopBinder.cs | 2 +- .../CSharp/Portable/BoundTree/BoundNodes.xml | 2 +- .../CSharp/Portable/BoundTree/Constructors.cs | 5 - .../Portable/CSharpResources.Designer.cs | 4 +- .../CSharp/Portable/CSharpResources.resx | 4 +- .../Semantics/TargetTypedDefaultTests.cs | 1243 ++++++++++++++--- .../Test/Utilities/CSharp/TestOptions.cs | 1 + .../ExpressionCompiler/SyntaxHelpers.cs | 6 +- .../ExpressionCompilerTests.cs | 104 ++ 10 files changed, 1184 insertions(+), 189 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index ab1d4354b28..c783ac88ae4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -2180,7 +2180,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper { UnaryOperatorKind kind = SyntaxKindToUnaryOperatorKind(node.Kind()); - bool isOperandTypeNull = (object)operand.Type == null; + bool isOperandTypeNull = operand.IsLiteralNull(); if (isOperandTypeNull) { // Dev10 does not allow unary prefix operators to be applied to the null literal diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs index 6ad80bf2c5b..349bf43ee58 100644 --- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs @@ -512,7 +512,7 @@ private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundE if ((object)collectionExprType == null) // There's no way to enumerate something without a type. { - if (collectionExpr.Kind == BoundKind.DefaultExpression && (object)collectionExpr.Type == null) + if (collectionExpr.Kind == BoundKind.DefaultExpression) { diagnostics.Add(ErrorCode.ERR_DefaultLiteralNotValid, _syntax.Expression.Location); } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index b2185dc49e3..0b1c5d5f77f 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -518,7 +518,7 @@ - + diff --git a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs index ba88cfda819..089b98202da 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/Constructors.cs @@ -529,11 +529,6 @@ public BoundDefaultExpression(SyntaxNode syntax, TypeSymbol type, bool hasErrors : this(syntax, type.GetDefaultValue(), type, hasErrors) { } - - public BoundDefaultExpression(SyntaxNode syntax) - : this(syntax, constantValueOpt: null, type: null, hasErrors: false) - { - } } internal partial class BoundTryStatement diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index eaae9af0c7f..483ea725baf 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -449,7 +449,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to Cannot assign {0} to anonymous type property. + /// Looks up a localized string similar to Cannot assign '{0}' to anonymous type property. /// internal static string ERR_AnonymousTypePropertyAssignedBadValue { get { @@ -8855,7 +8855,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to The switch expression must be a value; found {0}.. + /// Looks up a localized string similar to The switch expression must be a value; found '{0}'.. /// internal static string ERR_SwitchExpressionValueExpected { get { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index d2e3acc46d8..1d97a7c7ac9 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -2142,7 +2142,7 @@ If such a class is used as a base class and if the deriving class defines a dest No best type found for implicitly-typed array - Cannot assign {0} to anonymous type property + Cannot assign '{0}' to anonymous type property An expression tree may not contain a base access @@ -4886,7 +4886,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Deconstruct assignment requires an expression with a type on the right-hand-side. - The switch expression must be a value; found {0}. + The switch expression must be a value; found '{0}'. The switch case has already been handled by a previous case. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index 50737b151d9..c917c5c986a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs @@ -44,7 +44,7 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0"); @@ -60,6 +60,247 @@ static void Main() Assert.True(model.GetConversion(def).IsNullLiteral); } + [Fact] + public void AssignmentToThisOnRefType() + { + string source = @" +public class C +{ + public int field; + public C() => this = default; + public static void Main() + { + new C(); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (5,19): error CS1604: Cannot assign to 'this' because it is read-only + // public C() => this = default; + Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "this").WithArguments("this").WithLocation(5, 19) + ); + } + + [Fact] + public void AssignmentToThisOnStructType() + { + string source = @" +public struct S +{ + public int field; + public S(int x) => this = default; + public static void Main() + { + new S(1); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(0); + Assert.Equal("default", def.ToString()); + Assert.Equal("S", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Equal("S", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void InAttributeParameter() + { + string source = @" +[Custom(z: default, y: default, x: default)] +class C +{ + [Custom(default, default)] + void M() + { + } +} +public class CustomAttribute : System.Attribute +{ + public CustomAttribute(int x, string y, byte z = 0) { } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics(); + } + + [Fact] + public void InStringInterpolation() + { + string source = @" +class C +{ + static void Main() + { + System.Console.Write($""({default}) ({null})""); + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "() ()"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(0); + Assert.Equal("default", def.ToString()); + Assert.Null(model.GetTypeInfo(def).Type); // Should be given a type. Follow-up issue: https://github.com/dotnet/roslyn/issues/18609 + Assert.Null(model.GetTypeInfo(def).ConvertedType); + Assert.Null(model.GetSymbolInfo(def).Symbol); + Assert.False(model.GetConstantValue(def).HasValue); + Assert.False(model.GetConversion(def).IsNullLiteral); + + var nullSyntax = nodes.OfType().ElementAt(1); + Assert.Equal("null", nullSyntax.ToString()); + Assert.Null(model.GetTypeInfo(nullSyntax).Type); + Assert.Null(model.GetTypeInfo(nullSyntax).ConvertedType); // Should be given a type. Follow-up issue: https://github.com/dotnet/roslyn/issues/18609 + Assert.Null(model.GetSymbolInfo(nullSyntax).Symbol); + } + + [Fact] + public void InUsing() + { + string source = @" +class C +{ + static void Main() + { + using (default) + { + System.Console.Write(""ok""); + } + using (null) { } + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ok"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(0); + Assert.Equal("default", def.ToString()); + Assert.Null(model.GetTypeInfo(def).Type); + Assert.Null(model.GetTypeInfo(def).ConvertedType); // Should get a type. Follow-up issue: https://github.com/dotnet/roslyn/issues/18609 + Assert.Null(model.GetSymbolInfo(def).Symbol); + Assert.False(model.GetConstantValue(def).HasValue); + Assert.False(model.GetConversion(def).IsNullLiteral); + + var nullSyntax = nodes.OfType().ElementAt(2); + Assert.Equal("null", nullSyntax.ToString()); + Assert.Null(model.GetTypeInfo(nullSyntax).Type); + Assert.Null(model.GetTypeInfo(nullSyntax).ConvertedType); // Should get a type. Follow-up issue: https://github.com/dotnet/roslyn/issues/18609 + } + + [Fact] + public void CannotAwaitDefault() + { + string source = @" +class C +{ + async System.Threading.Tasks.Task M() + { + await default; + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics( + // (6,9): error CS4001: Cannot await 'default' + // await default; + Diagnostic(ErrorCode.ERR_BadAwaitArgIntrinsic, "await default").WithArguments("default").WithLocation(6, 9) + ); + } + + [Fact] + public void ReturningDefaultFromAsyncMethod() + { + string source = @" +using System.Threading.Tasks; +class C +{ + async Task M2() + { + await Task.Delay(0); + return default; + } +} +"; + + var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(1); + Assert.Equal("default", def.ToString()); + Assert.Equal("T", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Equal("T", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); + Assert.Null(model.GetSymbolInfo(def).Symbol); + Assert.False(model.GetConstantValue(def).HasValue); + Assert.True(model.GetConversion(def).IsNullLiteral); + } + + [Fact] + public void AsyncLambda() + { + string source = @" +class C +{ + static void F(System.Threading.Tasks.Task t) { } + + static void M() + { + F(async () => await default); + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics( + // (8,9): error CS0411: The type arguments for method 'C.F(Task)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // F(async () => await default); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("C.F(System.Threading.Tasks.Task)").WithLocation(8, 9) + ); + } + + [Fact] + public void RefReturnValue() + { + string source = @" +class C +{ + ref int M() + { + return default; + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics( + // (6,9): error CS8150: By-value returns may only be used in methods that return by value + // return default; + Diagnostic(ErrorCode.ERR_MustHaveRefReturn, "return").WithLocation(6, 9) + ); + } + [Fact] public void BadAssignment() { @@ -72,7 +313,7 @@ static void M() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics( // (6,13): error CS0815: Cannot assign default to an implicitly-typed variable // var x4 = default; @@ -98,7 +339,7 @@ static void M() } interface ITest { } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); } @@ -115,7 +356,7 @@ static void M() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); @@ -143,7 +384,7 @@ static void M() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.First(); @@ -172,7 +413,7 @@ static void Main() static void M(string x) { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(int)' and 'C.M(string)' // M(default); @@ -193,310 +434,871 @@ static void Main() static void M(string x) { System.Console.Write(x == null ? ""null"" : ""bad""); } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - CompileAndVerify(comp, expectedOutput: "null"); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "null"); + } + + [Fact] + public void MethodWithNullableParameters() + { + string source = @" +class C +{ + static void Main() + { + M(default); + } + static void M(int? x) { System.Console.Write(x.HasValue ? ""bad"" : ""null""); } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "null"); + } + + [Fact] + public void CannotInferTypeArg() + { + string source = @" +class C +{ + static void Main() + { + M(default); + } + static void M(T x) { } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (6,9): error CS0411: The type arguments for method 'C.M(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // M(default); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T)").WithLocation(6, 9) + ); + } + + [Fact] + public void CannotInferTypeArg2() + { + string source = @" +class C +{ + static void Main() + { + M(default, null); + } + static void M(T x, T y) where T : class { } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (6,9): error CS0411: The type arguments for method 'C.M(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // M(default, null); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T, T)").WithLocation(6, 9) + ); + } + + [Fact] + public void InvocationOnDefault() + { + string source = @" +class C +{ + static void Main() + { + default.ToString(); + default[0].ToString(); + System.Console.Write(nameof(default)); + throw default; + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (6,16): error CS0023: Operator '.' cannot be applied to operand of type 'default' + // default.ToString(); + Diagnostic(ErrorCode.ERR_BadUnaryOp, ".").WithArguments(".", "default").WithLocation(6, 16), + // (7,9): error CS0021: Cannot apply indexing with [] to an expression of type 'default' + // default[0].ToString(); + Diagnostic(ErrorCode.ERR_BadIndexLHS, "default[0]").WithArguments("default").WithLocation(7, 9), + // (8,37): error CS8081: Expression does not have a name. + // System.Console.Write(nameof(default)); + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "default").WithLocation(8, 37), + // (9,15): error CS0155: The type caught or thrown must be derived from System.Exception + // throw default; + Diagnostic(ErrorCode.ERR_BadExceptionType, "default").WithLocation(9, 15) + ); + } + + [Fact] + public void Cast() + { + string source = @" +class C +{ + static void Main() + { + int x = (int)default; + System.Console.Write(x); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0"); + } + + [Fact] + public void GenericCast() + { + string source = @" +class C +{ + static void M() + { + const T x = default(T); + const T y = (T)default; + const object z = (T)default; + System.Console.Write($""{x} {y} {z}""); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics( + // (6,15): error CS0283: The type 'T' cannot be declared const + // const T x = default(T); + Diagnostic(ErrorCode.ERR_BadConstType, "T").WithArguments("T").WithLocation(6, 15), + // (7,15): error CS0283: The type 'T' cannot be declared const + // const T y = (T)default; + Diagnostic(ErrorCode.ERR_BadConstType, "T").WithArguments("T").WithLocation(7, 15), + // (8,26): error CS0133: The expression being assigned to 'z' must be constant + // const object z = (T)default; + Diagnostic(ErrorCode.ERR_NotConstantExpression, "(T)default").WithArguments("z").WithLocation(8, 26) + ); + } + + [Fact] + public void UserDefinedStruct() + { + string source = @" +struct S { } +class C +{ + static void M() + { + const S x = default(S); + const S y = (S)default; + const object z = (S)default; + System.Console.Write($""{x} {y} {z}""); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics( + // (7,15): error CS0283: The type 'S' cannot be declared const + // const S x = default(S); + Diagnostic(ErrorCode.ERR_BadConstType, "S").WithArguments("S").WithLocation(7, 15), + // (8,15): error CS0283: The type 'S' cannot be declared const + // const S y = (S)default; + Diagnostic(ErrorCode.ERR_BadConstType, "S").WithArguments("S").WithLocation(8, 15), + // (9,26): error CS0133: The expression being assigned to 'z' must be constant + // const object z = (S)default; + Diagnostic(ErrorCode.ERR_NotConstantExpression, "(S)default").WithArguments("z").WithLocation(9, 26) + ); + } + + [Fact] + public void ImplicitlyTypedArray() + { + string source = @" +class C +{ + static void Main() + { + var t = new[] { 1, default }; + System.Console.Write(t[1]); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(1); + Assert.Equal("default", def.ToString()); + Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Equal("System.Int32", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); + Assert.Null(model.GetSymbolInfo(def).Symbol); + Assert.Equal("0", model.GetConstantValue(def).Value.ToString()); + } + + [Fact] + public void CollectionInitializer() + { + string source = @" +class C +{ + static void Main() + { + var t = new System.Collections.Generic.List { 1, default }; + System.Console.Write($""{t[0]} {t[1]}""); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "1 0"); + } + + [Fact] + public void MiscDefaultErrors() + { + string source = @" +class C +{ + static void Main() + { + switch (default) + { + default: + break; + } + lock (default) + { + } + default(); + + int i = ++default; + var anon = new { Name = default }; + System.TypedReference tr = __makeref(default); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (14,17): error CS1031: Type expected + // default(); + Diagnostic(ErrorCode.ERR_TypeExpected, ")").WithLocation(14, 17), + // (6,17): error CS8119: The switch expression must be a value; found 'default'. + // switch (default) + Diagnostic(ErrorCode.ERR_SwitchExpressionValueExpected, "default").WithArguments("default").WithLocation(6, 17), + // (11,15): error CS0185: 'default' is not a reference type as required by the lock statement + // lock (default) + Diagnostic(ErrorCode.ERR_LockNeedsReference, "default").WithArguments("default").WithLocation(11, 15), + // (16,19): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer + // int i = ++default; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "default").WithLocation(16, 19), + // (17,26): error CS0828: Cannot assign 'default' to anonymous type property + // var anon = new { Name = default }; + Diagnostic(ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, "Name = default").WithArguments("default").WithLocation(17, 26), + // (18,46): error CS1510: A ref or out value must be an assignable variable + // System.TypedReference tr = __makeref(default); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "default").WithLocation(18, 46) + ); + } + + [Fact] + public void InChecked() + { + string source = @" +class C +{ + static void Main() + { + int i = checked(default); + int j = checked(default + 4); + System.Console.Write($""{i} {j}""); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0 4"); + } + + [Fact] + public void WithUserDefinedPlusOperator() + { + string source = @" +struct S +{ + int field; + static void Main() + { + S s = new S(40) + default; + s += new S(2); + s += default; + System.Console.Write(s); + } + S(int i) { field = i; } + public static S operator +(S left, S right) => new S(left.field + right.field); + public override string ToString() => field.ToString(); +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "42"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var first = nodes.OfType().ElementAt(1); + Assert.Equal("new S(40) + default", first.Parent.ToString()); + Assert.Equal("S", model.GetTypeInfo(first).Type.ToTestDisplayString()); + + var second = nodes.OfType().ElementAt(3); + Assert.Equal("s += default", second.Parent.ToString()); + Assert.Equal("S", model.GetTypeInfo(second).Type.ToTestDisplayString()); + } + + [Fact] + public void WithUserDefinedEqualityOperator() + { + string source = @" +struct S +{ + static void Main() + { + if (new S() == default) + { + System.Console.Write(""branch reached.""); + } + } + public static bool operator ==(S left, S right) { System.Console.Write(""operator reached. ""); return true; } + public static bool operator !=(S left, S right) => false; + public override bool Equals(object o) => throw null; + public override int GetHashCode() => throw null; +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "operator reached. branch reached."); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var first = nodes.OfType().ElementAt(0); + Assert.Equal("default", first.ToString()); + Assert.Equal("S", model.GetTypeInfo(first).Type.ToTestDisplayString()); + } + + [Fact] + public void RefTypeAndValue() + { + string source = @" +class C +{ + static void Main() + { + System.Console.Write(1); + var t = __reftype(default); + System.Console.Write(2); + try + { + int rv = __refvalue(default, int); + } + catch (System.InvalidCastException) + { + System.Console.Write($""3: {t == null}""); + } + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "123: True"); + } + + [Fact] + public void InCompoundAssignmentAndExceptionFilter() + { + string source = @" +class C +{ + static void Main() + { + try + { + int i = 2; + i += default; + bool b = true; + b &= default; + System.Console.Write($""{true | default} {i} {b}""); + throw new System.Exception(); + } + catch (System.Exception) when (default) + { + System.Console.Write(""catch""); + } + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (15,40): warning CS7095: Filter expression is a constant, consider removing the filter + // catch (System.Exception) when (default) + Diagnostic(ErrorCode.WRN_FilterIsConstant, "default").WithLocation(15, 40), + // (17,13): warning CS0162: Unreachable code detected + // System.Console.Write("catch"); + Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(17, 13) + ); + //CompileAndVerify(comp, expectedOutput: "True 2 False"); // PEVerify failed with Branch out of the method. Follow-up issue: https://github.com/dotnet/roslyn/issues/18678 + } + + [Fact] + public void PEVerifyErrorWithFalse() + { + string source = @" +class C +{ + static void Main() + { + try + { + throw new System.Exception(); + } + catch (System.Exception) when (false) + { + System.Console.Write(""catch""); + } + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (10,40): warning CS7095: Filter expression is a constant, consider removing the filter + // catch (System.Exception) when (false) + Diagnostic(ErrorCode.WRN_FilterIsConstant, "false").WithLocation(10, 40), + // (12,13): warning CS0162: Unreachable code detected + // System.Console.Write("catch"); + Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(12, 13) + ); + //CompileAndVerify(comp); // PEVerify failed with Branch out of the method. Follow-up issue: https://github.com/dotnet/roslyn/issues/18678 + } + + [Fact] + public void NegationUnaryOperatorOnDefault() + { + string source = @" +class C +{ + static void Main() + { + if (!default) + { + System.Console.WriteLine(""reached""); + } + } +}"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "reached"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var def = tree.GetCompilationUnitRoot().DescendantNodes().OfType().ElementAt(0); + Assert.Equal("default", def.ToString()); + Assert.Equal("System.Boolean", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Equal("System.Boolean", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); + } + + [Fact] + public void NegationUnaryOperatorOnTypelessExpressions() + { + string source = @" +class C +{ + static void Main() + { + if (!Main || !null) + { + } + } +}"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (6,13): error CS0023: Operator '!' cannot be applied to operand of type 'method group' + // if (!Main || !null) + Diagnostic(ErrorCode.ERR_BadUnaryOp, "!Main").WithArguments("!", "method group"), + // (6,22): error CS0023: Operator '!' cannot be applied to operand of type '' + // if (!Main || !null) + Diagnostic(ErrorCode.ERR_BadUnaryOp, "!null").WithArguments("!", "").WithLocation(6, 22) + ); + } + + [Fact] + public void ConditionalOnDefault() + { + string source = @" +class C +{ + static void Main() + { + if (default) + { + System.Console.Write(""if""); + } + + while (default) + { + System.Console.Write(""while""); + } + + for (int i = 0; default; i++) + { + System.Console.Write(""for""); + } + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (8,13): warning CS0162: Unreachable code detected + // System.Console.Write("if"); + Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(8, 13), + // (13,13): warning CS0162: Unreachable code detected + // System.Console.Write("while"); + Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(13, 13), + // (18,13): warning CS0162: Unreachable code detected + // System.Console.Write("for"); + Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(18, 13) + ); } [Fact] - public void MethodWithNullableParameters() + public void ConditionalOnDefaultIsFalse() { string source = @" class C { static void Main() { - M(default); + if (default == false) + { + System.Console.Write(""reached""); + } + if (default == true) + { + System.Console.Write(""NEVER""); + } } - static void M(int? x) { System.Console.Write(x.HasValue ? ""bad"" : ""null""); } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - CompileAndVerify(comp, expectedOutput: "null"); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics( + // (12,13): warning CS0162: Unreachable code detected + // System.Console.Write("NEVER"); + Diagnostic(ErrorCode.WRN_UnreachableCode, "System").WithLocation(12, 13) + ); + CompileAndVerify(comp, expectedOutput: "reached"); } [Fact] - public void CannotInferTypeArg() + public void InFixed() { string source = @" class C { - static void Main() + static unsafe void Main() { - M(default); + fixed (byte* p = default) + { + } + fixed (byte* p = &default) + { + } } - static void M(T x) { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe.WithAllowUnsafe(true)); comp.VerifyDiagnostics( - // (6,9): error CS0411: The type arguments for method 'C.M(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. - // M(default); - Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T)").WithLocation(6, 9) + // (6,26): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression + // fixed (byte* p = default) + Diagnostic(ErrorCode.ERR_FixedNotNeeded, "default"), + // (9,27): error CS0211: Cannot take the address of the given expression + // fixed (byte* p = &default) + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "default").WithLocation(9, 27) ); } [Fact] - public void CannotInferTypeArg2() + public void Dereference() { string source = @" class C { - static void Main() + static void M() { - M(default, null); + var p = *default; + var q = default->F; } - static void M(T x, T y) where T : class { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics( - // (6,9): error CS0411: The type arguments for method 'C.M(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. - // M(default, null); - Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "M").WithArguments("C.M(T, T)").WithLocation(6, 9) + // (6,17): error CS0193: The * or -> operator must be applied to a pointer + // var p = *default; + Diagnostic(ErrorCode.ERR_PtrExpected, "*default").WithLocation(6, 17), + // (7,17): error CS0193: The * or -> operator must be applied to a pointer + // var q = default->F; + Diagnostic(ErrorCode.ERR_PtrExpected, "default->F").WithLocation(7, 17) ); } [Fact] - public void InvocationOnDefault() + public void FailedImplicitlyTypedArray() { string source = @" class C { static void Main() { - default.ToString(); - default[0].ToString(); - System.Console.Write(nameof(default)); - throw default; + var t = new[] { default, default }; } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( - // (6,16): error CS0023: Operator '.' cannot be applied to operand of type 'default' - // default.ToString(); - Diagnostic(ErrorCode.ERR_BadUnaryOp, ".").WithArguments(".", "default").WithLocation(6, 16), - // (7,9): error CS0021: Cannot apply indexing with [] to an expression of type 'default' - // default[0].ToString(); - Diagnostic(ErrorCode.ERR_BadIndexLHS, "default[0]").WithArguments("default").WithLocation(7, 9), - // (8,37): error CS8081: Expression does not have a name. - // System.Console.Write(nameof(default)); - Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "default").WithLocation(8, 37), - // (9,15): error CS0155: The type caught or thrown must be derived from System.Exception - // throw default; - Diagnostic(ErrorCode.ERR_BadExceptionType, "default").WithLocation(9, 15) + // (6,17): error CS0826: No best type found for implicitly-typed array + // var t = new[] { default, default }; + Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { default, default }").WithLocation(6, 17) ); } [Fact] - public void Cast() + public void ArrayConstruction() { string source = @" class C { static void Main() { - int x = (int)default; - System.Console.Write(x); + var t = new object[default]; } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); - comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "0"); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyDiagnostics(); } [Fact] - public void GenericCast() + public void Tuple() { string source = @" class C { - static void M() + static void Main() { - const T x = default(T); - const T y = (T)default; - const object z = (T)default; - System.Console.Write($""{x} {y} {z}""); + (int, int) t = (1, default); + System.Console.Write(t.Item2); } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); - comp.VerifyDiagnostics( - // (6,15): error CS0283: The type 'T' cannot be declared const - // const T x = default(T); - Diagnostic(ErrorCode.ERR_BadConstType, "T").WithArguments("T").WithLocation(6, 15), - // (7,15): error CS0283: The type 'T' cannot be declared const - // const T y = (T)default; - Diagnostic(ErrorCode.ERR_BadConstType, "T").WithArguments("T").WithLocation(7, 15), - // (8,26): error CS0133: The expression being assigned to 'z' must be constant - // const object z = (T)default; - Diagnostic(ErrorCode.ERR_NotConstantExpression, "(T)default").WithArguments("z").WithLocation(8, 26) - ); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe, + references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0"); } [Fact] - public void UserDefinedStruct() + public void TypeInferenceSucceeds() { string source = @" -struct S { } class C { - static void M() + static void Main() { - const S x = default(S); - const S y = (S)default; - const object z = (S)default; - System.Console.Write($""{x} {y} {z}""); + M(default, 1); } + static void M(T x, T y) { System.Console.Write(x); } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); - comp.VerifyDiagnostics( - // (7,15): error CS0283: The type 'S' cannot be declared const - // const S x = default(S); - Diagnostic(ErrorCode.ERR_BadConstType, "S").WithArguments("S").WithLocation(7, 15), - // (8,15): error CS0283: The type 'S' cannot be declared const - // const S y = (S)default; - Diagnostic(ErrorCode.ERR_BadConstType, "S").WithArguments("S").WithLocation(8, 15), - // (9,26): error CS0133: The expression being assigned to 'z' must be constant - // const object z = (S)default; - Diagnostic(ErrorCode.ERR_NotConstantExpression, "(S)default").WithArguments("z").WithLocation(9, 26) - ); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0"); } [Fact] - public void ImplicitlyTypedArray() + public void ArrayTypeInferredFromParams() { string source = @" class C { static void Main() { - var t = new[] { 1, default }; - System.Console.Write(t[1]); + M(default); + M(null); } + static void M(params object[] x) { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); - comp.VerifyDiagnostics(); - CompileAndVerify(comp, expectedOutput: "0"); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyEmitDiagnostics(); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().ElementAt(1); + var def = nodes.OfType().ElementAt(0); Assert.Equal("default", def.ToString()); - Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); - Assert.Equal("System.Int32", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); + Assert.Equal("System.Object[]", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Equal("System.Object[]", model.GetTypeInfo(def).ConvertedType.ToTestDisplayString()); Assert.Null(model.GetSymbolInfo(def).Symbol); - Assert.Equal("0", model.GetConstantValue(def).Value.ToString()); + Assert.Null(model.GetDeclaredSymbol(def)); + + var nullSyntax = nodes.OfType().ElementAt(1); + Assert.Equal("null", nullSyntax.ToString()); + Assert.Equal("System.Object[]", model.GetTypeInfo(nullSyntax).ConvertedType.ToTestDisplayString()); } [Fact] - public void FailedImplicitlyTypedArray() + public void ParamsAmbiguity() { string source = @" class C { static void Main() { - var t = new[] { default, default }; + M(default); } + static void M(params object[] x) { } + static void M(params int[] x) { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); - comp.VerifyDiagnostics( - // (6,17): error CS0826: No best type found for implicitly-typed array - // var t = new[] { default, default }; - Diagnostic(ErrorCode.ERR_ImplicitlyTypedArrayNoBestType, "new[] { default, default }").WithLocation(6, 17) + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyEmitDiagnostics( + // (6,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(params object[])' and 'C.M(params int[])' + // M(default); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(params object[])", "C.M(params int[])").WithLocation(6, 9) ); } [Fact] - public void ArrayConstruction() + public void ParamsAmbiguity2() { string source = @" class C { static void Main() { - var t = new object[default]; + M(default); } + static void M(params object[] x) { } + static void M(int x) { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); - comp.VerifyDiagnostics(); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); + comp.VerifyEmitDiagnostics( + // (6,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M(params object[])' and 'C.M(int)' + // M(default); + Diagnostic(ErrorCode.ERR_AmbigCall, "M").WithArguments("C.M(params object[])", "C.M(int)").WithLocation(6, 9) + ); } [Fact] - public void Tuple() + public void ParamsAmbiguity3() { string source = @" -class C +struct S { static void Main() { - (int, int) t = (1, default); - System.Console.Write(t.Item2); + object o = null; + S s = default; + M(o, default); + M(default, o); + M(s, default); + M(default, s); } + static void M(T x, params T[] y) { } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe, - references: new[] { ValueTupleRef, SystemRuntimeFacadeRef }); - + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "0"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var first = nodes.OfType().ElementAt(2); + Assert.Equal("(o, default)", first.Parent.Parent.ToString()); + Assert.Equal("System.Object[]", model.GetTypeInfo(first).Type.ToTestDisplayString()); + + var second = nodes.OfType().ElementAt(3); + Assert.Equal("(default, o)", second.Parent.Parent.ToString()); + Assert.Equal("System.Object", model.GetTypeInfo(second).Type.ToTestDisplayString()); + + var third = nodes.OfType().ElementAt(4); + Assert.Equal("(s, default)", third.Parent.Parent.ToString()); + Assert.Equal("S[]", model.GetTypeInfo(third).Type.ToTestDisplayString()); + + var fourth = nodes.OfType().ElementAt(5); + Assert.Equal("(default, s)", fourth.Parent.Parent.ToString()); + Assert.Equal("S", model.GetTypeInfo(fourth).Type.ToTestDisplayString()); } [Fact] - public void TypeInferenceSucceeds() + public void DefaultIdentifier() { string source = @" class C { static void Main() { - M(default, 1); + int @default = 2; + int x = default; + System.Console.Write($""{x} {@default}""); } - static void M(T x, T y) { System.Console.Write(x); } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "0"); + CompileAndVerify(comp, expectedOutput: "0 2"); + + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); + + var def = nodes.OfType().ElementAt(1); + Assert.Equal("default", def.ToString()); + Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); + Assert.Null(model.GetSymbolInfo(def).Symbol); + Assert.Null(model.GetDeclaredSymbol(def)); } [Fact] - public void DefaultIdentifier() + public void TestSpeculativeModel() { string source = @" class C { static void Main() { - int @default = 2; - int x = default; - System.Console.Write($""{x} {@default}""); + int i = 2; } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); - comp.VerifyEmitDiagnostics(); - CompileAndVerify(comp, expectedOutput: "0 2"); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var nodes = tree.GetCompilationUnitRoot().DescendantNodes(); - var def = nodes.OfType().ElementAt(1); - Assert.Equal("default", def.ToString()); - Assert.Equal("System.Int32", model.GetTypeInfo(def).Type.ToTestDisplayString()); - Assert.Null(model.GetSymbolInfo(def).Symbol); - Assert.Null(model.GetDeclaredSymbol(def)); + var digit = tree.GetCompilationUnitRoot().FindToken(source.IndexOf('2')); + var expressionSyntax = SyntaxFactory.ParseExpression("default"); + var typeInfo = model.GetSpeculativeTypeInfo(digit.SpanStart, expressionSyntax, SpeculativeBindingOption.BindAsExpression); + Assert.Null(typeInfo.Type); + var symbol = model.GetSpeculativeSymbolInfo(digit.SpanStart, expressionSyntax, SpeculativeBindingOption.BindAsExpression); + Assert.True(symbol.IsEmpty); } [Fact] @@ -511,7 +1313,7 @@ static int M() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); } @@ -532,7 +1334,29 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "0 1"); + } + + [Fact] + public void DefaultInTypedEnum() + { + string source = @" +enum E : byte +{ + DefaultEntry = default, + OneEntry = default + 1 +} +class C +{ + static void Main() + { + System.Console.Write($""{(byte)E.DefaultEntry} {(byte)E.OneEntry}""); + } +} +"; + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 1"); } @@ -555,7 +1379,7 @@ static IEnumerable M2() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); } @@ -571,7 +1395,7 @@ class C } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); } @@ -589,13 +1413,13 @@ static void Main() } } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyEmitDiagnostics(); CompileAndVerify(comp, expectedOutput: "0-0"); } [Fact] - public void DynamicInvocation() + public void InvocationOnDynamic() { string source = @" class C @@ -608,7 +1432,7 @@ static void M1() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics( // (7,14): error CS9000: Cannot use a default literal as an argument to a dynamically dispatched operation. // d.M2(default); @@ -616,6 +1440,28 @@ static void M1() ); } + [Fact] + public void DynamicInvocation() + { + string source = @" +class C +{ + static void Main() + { + F(default); + } + static void F(dynamic x) + { + System.Console.Write(x == null); + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, references: new[] { SystemCoreRef, CSharpRef }, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "True"); + } + [Fact] public void DefaultEqualsDefault() { @@ -629,7 +1475,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,33): error CS0034: Operator '==' is ambiguous on operands of type 'default' and 'default' // System.Console.Write($"{default == default} {default != default}"); @@ -655,7 +1501,7 @@ unsafe static void Main() } "; // Confusing, but matches Dev10. - CreateCompilationWithMscorlib(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.ExperimentalParseOptions) + CreateCompilationWithMscorlib(text, options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.Regular7_1) .VerifyDiagnostics( // (6,25): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression // fixed (int* p = default) @@ -676,7 +1522,7 @@ static void Main() } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,27): error CS9001: Use of default literal is not valid in this context // foreach (int x in default) { } @@ -691,19 +1537,24 @@ static void Main() public void QueryOnDefault() { string source = -@"static class C +@"using System.Linq; +static class C { static void Main() { var q = from x in default select x; + var p = from x in new int[] { 1 } select default; } } "; - var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.ExperimentalParseOptions); + var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.Regular7_1, references: new[] { SystemCoreRef }); compilation.VerifyDiagnostics( - // (5,35): error CS9001: Use of default literal is not valid in this context + // (6,35): error CS9001: Use of default literal is not valid in this context // var q = from x in default select x; - Diagnostic(ErrorCode.ERR_DefaultLiteralNotValid, "select x").WithLocation(5, 35) + Diagnostic(ErrorCode.ERR_DefaultLiteralNotValid, "select x").WithLocation(6, 35), + // (7,43): error CS1942: The type of the expression in the select clause is incorrect. Type inference failed in the call to 'Select'. + // var p = from x in new int[] { 1 } select default; + Diagnostic(ErrorCode.ERR_QueryTypeInferenceFailed, "select").WithArguments("select", "Select").WithLocation(7, 43) ); } @@ -720,7 +1571,7 @@ static void Main() } } "; - var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); compilation.VerifyDiagnostics(); CompileAndVerify(compilation, expectedOutput: "5"); } @@ -738,7 +1589,7 @@ static void Main() } } "; - var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.ExperimentalParseOptions); + var compilation = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.Regular7_1); compilation.VerifyDiagnostics( // (5,30): warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?' // System.Console.Write((int?)1 == default); @@ -761,7 +1612,7 @@ static void Main() } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,15): error CS0155: The type caught or thrown must be derived from System.Exception // throw default; @@ -783,7 +1634,7 @@ class C } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (6,30): error CS0077: The as operator must be used with a reference type or nullable type ('long' is a non-nullable value type) // System.Console.Write(default as long); @@ -808,7 +1659,7 @@ static void Main() System.Console.Write($""{default as C == null} {default as string == null}""); } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,33): warning CS0458: The result of the expression is always 'null' of type 'C' // System.Console.Write($"{default as C == null} {default as string == null}"); @@ -820,6 +1671,26 @@ static void Main() CompileAndVerify(comp, expectedOutput: "True True"); } + [Fact] + public void DefaultInputToTypeTest() + { + var text = @" +static class C +{ + static void M() + { + System.Console.Write(default is C); + } +}"; + + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugDll); + comp.VerifyDiagnostics( + // (6,30): error CS0023: Operator 'is' cannot be applied to operand of type 'default' + // System.Console.Write(default is C); + Diagnostic(ErrorCode.ERR_BadUnaryOp, "default is C").WithArguments("is", "default").WithLocation(6, 30) + ); + } + [Fact] public void DefaultInputToConstantPattern() { @@ -835,7 +1706,7 @@ static void M() } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugDll); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugDll); comp.VerifyDiagnostics( // (6,30): error CS0023: Operator 'is' cannot be applied to operand of type 'default' // System.Console.Write(default is long); @@ -871,7 +1742,7 @@ static void Main() } }"; - var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "False True False True"); } @@ -909,7 +1780,7 @@ static void M() static T6 F6() { return default; } static T7 F7() { return default; } }"; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics(); } @@ -925,7 +1796,7 @@ class Program Expression> testExpr = () => default ?? ""hello""; }"; - var comp = CreateCompilationWithMscorlibAndSystemCore(text, parseOptions: TestOptions.ExperimentalParseOptions); + var comp = CreateCompilationWithMscorlibAndSystemCore(text, parseOptions: TestOptions.Regular7_1); comp.VerifyDiagnostics( // (6,47): error CS0845: An expression tree lambda may not contain a coalescing operator with a null or default literal left-hand side // Expression> testExpr = () => default ?? "hello"; @@ -946,7 +1817,7 @@ static void Main() } }"; - var comp = CreateCompilationWithMscorlibAndSystemCore(text, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlibAndSystemCore(text, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "False"); @@ -974,7 +1845,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "1"); } @@ -996,7 +1867,7 @@ static System.Func M() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0"); } @@ -1025,7 +1896,7 @@ static void M(int x) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (12,18): warning CS9002: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate. // case default: @@ -1058,7 +1929,7 @@ static void M(object x) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (12,18): warning CS9002: Did you mean to use the default switch label (`default:`) rather than `case default:`? If you really mean to use the default literal, consider `case (default):` or another literal (`case 0:` or `case null:`) as appropriate. // case default: @@ -1091,7 +1962,7 @@ static void M(int x) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "default"); } @@ -1120,7 +1991,7 @@ static void M(object x) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "default"); } @@ -1146,7 +2017,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "01"); } @@ -1168,11 +2039,33 @@ static void M(int x = default) } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0"); } + [Fact] + public void OptionalCancellationTokenParameter() + { + string source = @" +class C +{ + static void Main() + { + M(); + } + static void M(System.Threading.CancellationToken x = default) + { + System.Console.Write(""ran""); + } +} +"; + + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "ran"); + } + [Fact] public void ArraySize() { @@ -1187,7 +2080,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0"); } @@ -1207,7 +2100,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0 System.Int32"); } @@ -1227,7 +2120,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "null"); } @@ -1246,7 +2139,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics(); CompileAndVerify(comp, expectedOutput: "0"); @@ -1286,7 +2179,7 @@ static void Main() } "; - var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.ExperimentalParseOptions, options: TestOptions.DebugExe); + var comp = CreateCompilationWithMscorlib(source, parseOptions: TestOptions.Regular7_1, options: TestOptions.DebugExe); comp.VerifyDiagnostics( // (6,17): error CS0118: 'System' is a namespace but is used like a type // default(System).ToString(); diff --git a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs index 19741fb2539..0ec664f2163 100644 --- a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs +++ b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs @@ -14,6 +14,7 @@ public static class TestOptions public static readonly CSharpParseOptions Script = new CSharpParseOptions(kind: SourceCodeKind.Script, documentationMode: DocumentationMode.None); public static readonly CSharpParseOptions Regular = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None); public static readonly CSharpParseOptions Regular6 = Regular.WithLanguageVersion(LanguageVersion.CSharp6); + public static readonly CSharpParseOptions Regular7_1 = Regular.WithLanguageVersion(LanguageVersion.CSharp7_1); public static readonly CSharpParseOptions RegularWithDocumentationComments = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Diagnose); private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary { }; diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs index aa3af0b9601..c0f4f0fc2b3 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/SyntaxHelpers.cs @@ -194,9 +194,11 @@ private static ExpressionSyntax ParseDebuggerExpression(string text, bool consum return expression.MakeDebuggerExpression(source); } + static readonly CSharpParseOptions s_CSharpParseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); + private static InternalSyntax.ExpressionSyntax ParseDebuggerExpressionInternal(SourceText source, bool consumeFullText) { - using (var lexer = new InternalSyntax.Lexer(source, CSharpParseOptions.Default, allowPreprocessorDirectives: false)) + using (var lexer = new InternalSyntax.Lexer(source, s_CSharpParseOptions, allowPreprocessorDirectives: false)) { using (var parser = new InternalSyntax.LanguageParser(lexer, oldTree: null, changes: null, lexerMode: InternalSyntax.LexerMode.DebuggerSyntax)) { @@ -210,7 +212,7 @@ private static InternalSyntax.ExpressionSyntax ParseDebuggerExpressionInternal(S private static StatementSyntax ParseDebuggerStatement(string text) { var source = SourceText.From(text); - using (var lexer = new InternalSyntax.Lexer(source, CSharpParseOptions.Default)) + using (var lexer = new InternalSyntax.Lexer(source, s_CSharpParseOptions)) { using (var parser = new InternalSyntax.LanguageParser(lexer, oldTree: null, changes: null, lexerMode: InternalSyntax.LexerMode.DebuggerSyntax)) { diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index 617f9471593..929fd4cd108 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -6205,5 +6205,109 @@ .maxstack 3 }"); }); } + + [Fact] + public void AssignDefaultToLocal() + { + var source = @" +class C +{ + void Test() + { + int a = 1; + } +} +"; + var comp = CreateCompilationWithMscorlib(source, options: TestOptions.DebugDll, parseOptions: TestOptions.Regular); + WithRuntimeInstance(comp, runtime => + { + var context = CreateMethodContext(runtime, methodName: "C.Test"); + + ResultProperties resultProperties; + string error; + var testData = new CompilationTestData(); + ImmutableArray missingAssemblyIdentities; + context.CompileAssignment("a", "default", NoAliases, DebuggerDiagnosticFormatter.Instance, out resultProperties, out error, out missingAssemblyIdentities, EnsureEnglishUICulture.PreferredOrNull, testData); + Assert.Null(error); + Assert.Empty(missingAssemblyIdentities); + + Assert.Equal(DkmClrCompilationResultFlags.PotentialSideEffect, resultProperties.Flags); + Assert.Equal(default(DkmEvaluationResultCategory), resultProperties.Category); // Not Data + Assert.Equal(default(DkmEvaluationResultAccessType), resultProperties.AccessType); // Not Public + Assert.Equal(default(DkmEvaluationResultStorageType), resultProperties.StorageType); + Assert.Equal(default(DkmEvaluationResultTypeModifierFlags), resultProperties.ModifierFlags); // Not Virtual + testData.GetMethodData("<>x.<>m0").VerifyIL(@" +{ + // Code size 3 (0x3) + .maxstack 1 + .locals init (int V_0) //a + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: ret +}"); + + testData = new CompilationTestData(); + context.CompileExpression("a = default;", DkmEvaluationFlags.None, ImmutableArray.Empty, out error, testData); + Assert.Null(error); + testData.GetMethodData("<>x.<>m0").VerifyIL(@" +{ + // Code size 4 (0x4) + .maxstack 2 + .locals init (int V_0) //a + IL_0000: ldc.i4.0 + IL_0001: dup + IL_0002: stloc.0 + IL_0003: ret +}"); + testData = new CompilationTestData(); + context.CompileExpression("int b = default;", DkmEvaluationFlags.None, ImmutableArray.Empty, out error, testData); + Assert.Null(error); + testData.GetMethodData("<>x.<>m0").VerifyIL(@" +{ + // Code size 43 (0x2b) + .maxstack 4 + .locals init (int V_0, //a + System.Guid V_1) + IL_0000: ldtoken ""int"" + IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"" + IL_000a: ldstr ""b"" + IL_000f: ldloca.s V_1 + IL_0011: initobj ""System.Guid"" + IL_0017: ldloc.1 + IL_0018: ldnull + IL_0019: call ""void Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, string, System.Guid, byte[])"" + IL_001e: ldstr ""b"" + IL_0023: call ""int Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(string)"" + IL_0028: ldc.i4.0 + IL_0029: stind.i4 + IL_002a: ret +}"); + + testData = new CompilationTestData(); + context.CompileExpression("default", DkmEvaluationFlags.None, ImmutableArray.Empty, out error, testData); + Assert.Null(error); + testData.GetMethodData("<>x.<>m0").VerifyIL(@" +{ + // Code size 2 (0x2) + .maxstack 1 + .locals init (int V_0) //a + IL_0000: ldnull + IL_0001: ret +}"); + Assert.Equal(SpecialType.System_Object, testData.GetMethodData("<>x.<>m0").Method.ReturnType.SpecialType); + + testData = new CompilationTestData(); + context.CompileExpression("null", DkmEvaluationFlags.None, ImmutableArray.Empty, out error, testData); + Assert.Null(error); + testData.GetMethodData("<>x.<>m0").VerifyIL(@" +{ + // Code size 2 (0x2) + .maxstack 1 + .locals init (int V_0) //a + IL_0000: ldnull + IL_0001: ret +}"); + }); + } } } -- GitLab