Add coalesce operator
authora-shaurtaev <a.shaurtaev@partner.samsung.com>
Mon, 18 Oct 2021 12:41:44 +0000 (15:41 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Fri, 19 Nov 2021 15:32:46 +0000 (18:32 +0300)
src/debugger/evalstackmachine.cpp
src/managed/StackMachine.cs
test-suite/MITestEvaluate/Program.cs
test-suite/VSCodeTestEvaluate/Program.cs

index b545561e70c16bda87bb509babc6eda1d9564099..44678c71c631b99bac930b575c4af946c57afebe 100644 (file)
@@ -1642,8 +1642,49 @@ namespace
 
     HRESULT CoalesceExpression(std::list<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
     {
-        // TODO uint32_t Flags = ((FormatF*)pArguments)->Flags;
-        return E_NOTIMPL;
+        HRESULT Status;
+        ToRelease<ICorDebugValue> iCorRealValueRightOp;
+        ToRelease<ICorDebugValue> iCorRightOpValue;
+        CorElementType elemTypeRightOp;
+        IfFailRet(GetFrontStackEntryValue(&iCorRightOpValue, evalStack, ed, output));
+        IfFailRet(GetRealValueWithType(iCorRightOpValue, &iCorRealValueRightOp, &elemTypeRightOp));
+        auto rightOperand = std::move(evalStack.front());
+        evalStack.pop_front();
+
+        ToRelease<ICorDebugValue> iCorRealValueLeftOp;
+        ToRelease<ICorDebugValue> iCorLeftOpValue;
+        CorElementType elemTypeLeftOp;
+        IfFailRet(GetFrontStackEntryValue(&iCorLeftOpValue, evalStack, ed, output));
+        IfFailRet(GetRealValueWithType(iCorLeftOpValue, &iCorRealValueLeftOp, &elemTypeLeftOp));
+        std::string typeNameLeft;
+        std::string typeNameRigth;
+
+        //TODO add implementation for object type ?? other
+        if((elemTypeRightOp == ELEMENT_TYPE_STRING && elemTypeLeftOp == ELEMENT_TYPE_STRING)
+           || ((elemTypeRightOp == ELEMENT_TYPE_CLASS && elemTypeLeftOp == ELEMENT_TYPE_CLASS)
+              && SUCCEEDED(TypePrinter::NameForTypeByValue(iCorRealValueLeftOp, typeNameLeft))
+              && SUCCEEDED(TypePrinter::NameForTypeByValue(iCorRealValueRightOp, typeNameRigth))
+              && typeNameLeft == typeNameRigth))
+        {
+            ToRelease<ICorDebugReferenceValue> pRefValue;
+            IfFailRet(iCorLeftOpValue->QueryInterface(IID_ICorDebugReferenceValue, (LPVOID*) &pRefValue));
+            BOOL isNull = FALSE;
+            IfFailRet(pRefValue->IsNull(&isNull));
+
+            if (isNull == TRUE)
+            {
+                evalStack.pop_front();
+                evalStack.push_front(std::move(rightOperand));
+            }
+            return S_OK;
+        }
+        //TODO add proccesing for parent-child class relationship
+        std::string typeName1;
+        std::string typeName2;
+        IfFailRet(TypePrinter::GetTypeOfValue(iCorRealValueLeftOp, typeName1));
+        IfFailRet(TypePrinter::GetTypeOfValue(iCorRealValueRightOp, typeName2));
+        output = "error CS0019: Operator ?? cannot be applied to operands of type '" + typeName1 + "' and '" + typeName2 + "'";
+        return E_INVALIDARG;
     }
 
     HRESULT ThisExpression(std::list<EvalStackEntry> &evalStack, PVOID pArguments, std::string &output, EvalData &ed)
index 93a851b06bc79785ce5767a5a0894a9a8e4e0649..4bb451a1dfd06f97e7183593245341c8eeccd856 100644 (file)
@@ -706,6 +706,7 @@ namespace NetCoreDbg
                         case SyntaxKind.GreaterThanOrEqualExpression:
                         case SyntaxKind.LessThanOrEqualExpression:
                         case SyntaxKind.QualifiedName:
+                        case SyntaxKind.CoalesceExpression:
 
 /* TODO
                         case SyntaxKind.AliasQualifiedName:
@@ -722,7 +723,6 @@ namespace NetCoreDbg
                         case SyntaxKind.SizeOfExpression:
 /*
                         case SyntaxKind.TypeOfExpression:
-                        case SyntaxKind.CoalesceExpression:
 */
                             stackMachineProgram.Commands.Add(new NoOperandsCommand(node.Kind(), CurrentScopeFlags.Peek()));
                             break;
index 88c23ed0ac21f60897b9d87d8697510ba79ce3b1..6fde62243d6dedba214e6bb2ac89628f3878f490 100644 (file)
@@ -475,6 +475,17 @@ namespace MITestEvaluate
             return 10;
         }
     }
+
+    public class coalesce_test_A
+    {
+        public string A = "A";
+    }
+
+    public class coalesce_test_B
+    {
+        public string B = "B";
+    }
+
     public class test_child : test_parent
     {
         public int i_child = 402;
@@ -687,6 +698,7 @@ namespace MITestEvaluate
                 Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK11");
                 Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK12");
                 Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK13");
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", "BREAK14");
                 Context.Continue(@"__FILE__:__LINE__");
             });
 
@@ -1385,13 +1397,96 @@ namespace MITestEvaluate
             });
 
             int break_line_13 = 13;                                                                           Label.Breakpoint("BREAK13");
-            Label.Checkpoint("function_evaluation_test", "finish", (Object context) => {
+            Label.Checkpoint("function_evaluation_test", "coalesce_test", (Object context) => {
                 Context Context = (Context)context;
                 Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK13");
 
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", "111", "int", "stGetInt()");
                 Context.GetAndCheckValue(@"__FILE__:__LINE__", "666", "int", "stGetInt(333)");
                 Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "getInt()", "Error:");
+                Context.Continue(@"__FILE__:__LINE__");
+            });
+            
+            coalesce_test_A test_null = null;
+            coalesce_test_A A_class = new coalesce_test_A();
+            coalesce_test_B B_class = new coalesce_test_B();
+
+            string str_null = null;
+            string A_string = "A";
+            string B_string = "B";
+            string C_string = "C";
+
+            test_struct1_t test_struct = new test_struct1_t();
+            decimal test_decimal = 1;
+            int test_int = 1;
+
+            int break_line14 = 1;                                                                        Label.Breakpoint("BREAK14");
+            Label.Checkpoint("coalesce_test", "finish", (Object context) => {
+                Context Context = (Context)context;
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK14");
+
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"first\\\"", "string", "\\\"first\\\".ToString()??\\\"second\\\".ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestEvaluate.coalesce_test_A}", "MITestEvaluate.coalesce_test_A", "A_class??test_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestEvaluate.coalesce_test_A}", "MITestEvaluate.coalesce_test_A", "test_null??A_class");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvaluate.coalesce_test_A", "test_null??test_null");
+
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestEvaluate.coalesce_test_A}", "MITestEvaluate.coalesce_test_A", "test_null??test_null??A_class");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestEvaluate.coalesce_test_A}", "MITestEvaluate.coalesce_test_A", "A_class??test_null??test_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "{MITestEvaluate.coalesce_test_A}", "MITestEvaluate.coalesce_test_A", "test_null??A_class??test_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvaluate.coalesce_test_A", "test_null??test_null??test_null");
+
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"B\\\"", "string", "str_null??B_string.ToString()??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"C\\\"", "string", "str_null??str_null??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"A\\\"", "string", "A_string.ToString()??str_null??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"A\\\"", "string", "A_string.ToString()??str_null??str_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"B\\\"", "string", "str_null??B_string.ToString()??str_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"A\\\"", "string", "A_string.ToString()??B_string.ToString()??str_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "\\\"A\\\"", "string", "A_string.ToString()??B_string.ToString()??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "null", "MITestEvaluate.coalesce_test_A", "test_null??test_null??test_null");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "A_string.ToString()??1", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "1??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "A_class??1", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "1??A_class", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "A_string.ToString()??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_int??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "A_class??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_int??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_int??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_null??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_int??test_int", "error CS0019");
+                
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__","A_string.ToString()??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_struct??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__","A_class??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_struct??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_null??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_struct??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_struct??test_struct", "error CS0019");
+                
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__","A_string.ToString()??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_decimal??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__","A_class??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_decimal??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_null??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_decimal??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_decimal??test_decimal", "error CS0019");
+                
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__","\\\"first\\\".ToString()??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_decimal??\\\"first\\\".ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "\\\"first\\\".ToString()??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_int??\\\"first\\\".ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "\\\"first\\\".ToString()??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_struct??\\\"first\\\".ToString()", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_null??\\\"first\\\".ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "\\\"first\\\".ToString()??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "test_null??str_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "A_class??B_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "B_class??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "B_class??str_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "str_null??B_class", "error CS0019");
 
                 Context.Continue(@"__FILE__:__LINE__");
             });
index bdd3d57ecc34b52f6bc083bbe845cc5b206a51a4..24bba8a220e1f04125df7987ad922fd5b68a6d1d 100644 (file)
@@ -645,6 +645,15 @@ namespace VSCodeTestEvaluate
         }
     }
 
+    public class coalesce_test_A
+    {
+        public string A = "A";
+    }
+    public class coalesce_test_B
+    {
+        public string B = "B";
+    }
+
     public class MethodCallTest2
     {
         public static MethodCallTest1 member1 = new MethodCallTest1();
@@ -805,6 +814,7 @@ namespace VSCodeTestEvaluate
                 Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK11");
                 Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK12");
                 Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK13");
+                Context.AddBreakpoint(@"__FILE__:__LINE__", "BREAK14");
                 Context.SetBreakpoints(@"__FILE__:__LINE__");
                 Context.PrepareEnd(@"__FILE__:__LINE__");
                 Context.WasEntryPointHit(@"__FILE__:__LINE__");
@@ -1509,7 +1519,7 @@ namespace VSCodeTestEvaluate
 
             int break_line13 = 13;                                                                        Label.Breakpoint("BREAK13");
 
-            Label.Checkpoint("function_evaluation_test", "finish", (Object context) => {
+            Label.Checkpoint("function_evaluation_test", "coalesce_test", (Object context) => {
                 Context Context = (Context)context;
                 Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK13");
                 Int64 frameId = Context.DetectFrameId(@"__FILE__:__LINE__", "BREAK13");
@@ -1521,6 +1531,91 @@ namespace VSCodeTestEvaluate
                 Context.Continue(@"__FILE__:__LINE__");
             });
 
+            coalesce_test_A test_null = null;
+            coalesce_test_A A_class = new coalesce_test_A();
+            coalesce_test_B B_class = new coalesce_test_B();
+
+            string str_null = null;
+            string A_string = "A";
+            string B_string = "B";
+            string C_string = "C";
+
+            test_struct1_t test_struct = new test_struct1_t();
+            decimal test_decimal = 1;
+            int test_int = 1;
+
+            int break_line14 = 1;                                                                        Label.Breakpoint("BREAK14");
+            Label.Checkpoint("coalesce_test", "finish", (Object context) => {
+                Context Context = (Context)context;
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", "BREAK14");
+                Int64 frameId = Context.DetectFrameId(@"__FILE__:__LINE__", "BREAK14");
+
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"first\"", "string", "\"first\".ToString()??\"second\".ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestEvaluate.coalesce_test_A}", "VSCodeTestEvaluate.coalesce_test_A", "A_class??test_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestEvaluate.coalesce_test_A}", "VSCodeTestEvaluate.coalesce_test_A", "test_null??A_class");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvaluate.coalesce_test_A", "test_null??test_null");
+
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestEvaluate.coalesce_test_A}", "VSCodeTestEvaluate.coalesce_test_A", "test_null??test_null??A_class");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestEvaluate.coalesce_test_A}", "VSCodeTestEvaluate.coalesce_test_A", "A_class??test_null??test_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "{VSCodeTestEvaluate.coalesce_test_A}", "VSCodeTestEvaluate.coalesce_test_A", "test_null??A_class??test_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvaluate.coalesce_test_A", "test_null??test_null??test_null");
+
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"B\"", "string", "str_null??B_string.ToString()??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"C\"", "string", "str_null??str_null??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"A\"", "string", "A_string.ToString()??str_null??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"A\"", "string", "A_string.ToString()??str_null??str_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"B\"", "string", "str_null??B_string.ToString()??str_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"A\"", "string", "A_string.ToString()??B_string.ToString()??str_null");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "\"A\"", "string", "A_string.ToString()??B_string.ToString()??C_string.ToString()");
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", frameId, "null", "VSCodeTestEvaluate.coalesce_test_A", "test_null??test_null??test_null");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_string.ToString()??1", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "1??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_class??1", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "1??A_class", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_string.ToString()??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_int??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_class??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_int??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_int??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_null??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_int??test_int", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_string.ToString()??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_struct??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_class??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_struct??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_null??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_struct??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_struct??test_struct", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_string.ToString()??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_decimal??A_string.ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_class??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_decimal??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_null??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_decimal??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_decimal??test_decimal", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "\"first\".ToString()??test_decimal", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_decimal??\"first\".ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "\"first\".ToString()??test_int", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_int??\"first\".ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "\"first\".ToString()??test_struct", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_struct??\"first\".ToString()", "error CS0019");
+
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_null??\"first\".ToString()", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "\"first\".ToString()??test_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "test_null??str_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "A_class??B_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "B_class??A_class", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "B_class??str_null", "error CS0019");
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", frameId, "str_null??B_class", "error CS0019");
+
+                Context.Continue(@"__FILE__:__LINE__");
+            });
+
             Label.Checkpoint("finish", "", (Object context) => {
                 Context Context = (Context)context;
                 Context.WasExit(@"__FILE__:__LINE__");