[mcs] Clean-up flow analysis for boolean expressions
authorMarek Safar <marek.safar@gmail.com>
Tue, 19 Aug 2014 15:10:33 +0000 (17:10 +0200)
committerMarek Safar <marek.safar@gmail.com>
Wed, 20 Aug 2014 06:20:26 +0000 (08:20 +0200)
mcs/errors/cs0165-49.cs [new file with mode: 0644]
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/statement.cs
mcs/tests/test-880.cs
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0165-49.cs b/mcs/errors/cs0165-49.cs
new file mode 100644 (file)
index 0000000..387a2df
--- /dev/null
@@ -0,0 +1,22 @@
+// CS0165: Use of unassigned local variable `a'
+// Line: 14
+
+class C
+{
+       static void Main ()
+       {
+               bool x = true, y = true, z = true;
+
+               int a;
+               if (x ? y : (z || Foo (out a)))
+                       System.Console.WriteLine (z);
+               else
+                       System.Console.WriteLine (a);
+       }
+
+       static bool Foo (out int f)
+       {
+               f = 1;
+               return true;
+       }
+}
\ No newline at end of file
index 149b07a16b669d58e55c2b0331e17e286a22913a..5729e21b3e7e9275a1fe18a577598f104e3fe16e 100644 (file)
@@ -995,6 +995,16 @@ namespace Mono.CSharp {
                {
                }
 
+               //
+               // Special version of flow analysis for expressions which can return different
+               // on-true and on-false result. Used by &&, ||, ?: expressions
+               //
+               public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       FlowAnalysis (fc);
+                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+               }
+
                /// <summary>
                ///   Returns an expression that can be used to invoke operator true
                ///   on the expression if it exists.
index f73e852818bb8c068678c75aa29050b596e3c388..5443ab37ac7f2b7482b938d79c26c0ca9c53308a 100644 (file)
@@ -610,6 +610,16 @@ namespace Mono.CSharp
                }
 
                public override void FlowAnalysis (FlowAnalysisContext fc)
+               {
+                       FlowAnalysis (fc, false);
+               }
+
+               public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       FlowAnalysis (fc, true);
+               }
+
+               void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
                {
                        if (Oper == Operator.AddressOf) {
                                var vr = Expr as VariableReference;
@@ -619,12 +629,14 @@ namespace Mono.CSharp
                                return;
                        }
 
-                       Expr.FlowAnalysis (fc);
+                       if (Oper == Operator.LogicalNot && conditional) {
+                               Expr.FlowAnalysisConditional (fc);
 
-                       if (Oper == Operator.LogicalNot) {
                                var temp = fc.DefiniteAssignmentOnTrue;
                                fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
                                fc.DefiniteAssignmentOnFalse = temp;
+                       } else {
+                               Expr.FlowAnalysis (fc);
                        }
                }
 
@@ -2621,43 +2633,44 @@ namespace Mono.CSharp
 
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
+                       //
+                       // Optimized version when on-true/on-false data are not needed
+                       //
                        if ((oper & Operator.LogicalMask) == 0) {
-                               fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
                                left.FlowAnalysis (fc);
-                               fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
                                right.FlowAnalysis (fc);
                                return;
                        }
 
-                       //
-                       // Optimized version when on-true/on-false data are not needed
-                       //
-                       bool set_on_true_false;
-                       if (fc.DefiniteAssignmentOnTrue == null && fc.DefiniteAssignmentOnFalse == null) {
-                               fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
-                               set_on_true_false = false;
-                       } else {
-                               set_on_true_false = true;
-                       }
-
-                       left.FlowAnalysis (fc);
+                       left.FlowAnalysisConditional (fc);
                        var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
                        var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
 
                        fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
                                oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
-                       right.FlowAnalysis (fc);
+                       right.FlowAnalysisConditional (fc);
 
-                       if (!set_on_true_false) {
-                               if (oper == Operator.LogicalOr)
-                                       fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
-                               else
-                                       fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
+                       if (oper == Operator.LogicalOr)
+                               fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
+                       else
+                               fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
+               }
 
-                               fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue = null;
+               public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       if ((oper & Operator.LogicalMask) == 0) {
+                               base.FlowAnalysisConditional (fc);
                                return;
                        }
 
+                       left.FlowAnalysisConditional (fc);
+                       var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
+                       var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
+
+                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
+                               oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
+                       right.FlowAnalysisConditional (fc);
+
                        var lc = left as Constant;
                        if (oper == Operator.LogicalOr) {
                                fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
@@ -5557,24 +5570,38 @@ namespace Mono.CSharp
 
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
-                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+                       expr.FlowAnalysisConditional (fc);
+                       var expr_true = fc.DefiniteAssignmentOnTrue;
+                       var expr_false = fc.DefiniteAssignmentOnFalse;
 
-                       expr.FlowAnalysis (fc);
-                       var da_true = fc.DefiniteAssignmentOnTrue;
-                       var da_false = fc.DefiniteAssignmentOnFalse;
-
-                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_true);
+                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
                        true_expr.FlowAnalysis (fc);
                        var true_fc = fc.DefiniteAssignment;
 
-                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (da_false);
+                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
                        false_expr.FlowAnalysis (fc);
 
                        fc.DefiniteAssignment &= true_fc;
-                       if (fc.DefiniteAssignmentOnTrue != null)
-                               fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignment;
-                       if (fc.DefiniteAssignmentOnFalse != null)
-                               fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
+               }
+
+               public override void FlowAnalysisConditional (FlowAnalysisContext fc)
+               {
+                       expr.FlowAnalysisConditional (fc);
+                       var expr_true = fc.DefiniteAssignmentOnTrue;
+                       var expr_false = fc.DefiniteAssignmentOnFalse;
+
+                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
+                       true_expr.FlowAnalysisConditional (fc);
+                       var true_fc = fc.DefiniteAssignment;
+                       var true_da_true = fc.DefiniteAssignmentOnTrue;
+                       var true_da_false = fc.DefiniteAssignmentOnFalse;
+
+                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
+                       false_expr.FlowAnalysisConditional (fc);
+
+                       fc.DefiniteAssignment &= true_fc;
+                       fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
+                       fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
                }
 
                protected override void CloneTo (CloneContext clonectx, Expression t)
index 1e377fe1448afe290fba48329fc26c3e651a47bd..5e673d485858e56dfdfc2f55137ae47b4ac8b9fd 100644 (file)
@@ -90,7 +90,6 @@ namespace Mono.CSharp {
                        if (reachable) {
                                fc.UnreachableReported = false;
                                var res = DoFlowAnalysis (fc);
-                               fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
                                return res;
                        }
 
@@ -266,14 +265,11 @@ namespace Mono.CSharp {
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
                {
-                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
-
-                       expr.FlowAnalysis (fc);
+                       expr.FlowAnalysisConditional (fc);
 
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
 
                        fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
-                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
 
                        var res = TrueStatement.FlowAnalysis (fc);
 
@@ -423,8 +419,7 @@ namespace Mono.CSharp {
                {
                        var res = Statement.FlowAnalysis (fc);
 
-                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
-                       expr.FlowAnalysis (fc);
+                       expr.FlowAnalysisConditional (fc);
 
                        fc.DefiniteAssignment = fc.DefiniteAssignmentOnFalse;
 
@@ -569,13 +564,10 @@ namespace Mono.CSharp {
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
                {
-                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
-       
-                       expr.FlowAnalysis (fc);
+                       expr.FlowAnalysisConditional (fc);
 
                        fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
-                       fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
 
                        Statement.FlowAnalysis (fc);
 
@@ -701,12 +693,9 @@ namespace Mono.CSharp {
 
                        DefiniteAssignmentBitSet da_false;
                        if (Condition != null) {
-                               fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
-
-                               Condition.FlowAnalysis (fc);
+                               Condition.FlowAnalysisConditional (fc);
                                fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
                                da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
-                               fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
                        } else {
                                da_false = fc.BranchDefiniteAssignment ();
                        }
index 6449d56406138d0b839d8e446a0b76dd4e203642..acb4a4d5a862c1fde5915d163dfa9b7f3149387e 100644 (file)
@@ -57,7 +57,18 @@ public class A
        {
                int f = 1;
                int g;
-        return f > 1 && OutCall (out g) && g > 1;
+               return f > 1 && OutCall (out g) && g > 1;
+       }
+
+       static void Test8 ()
+       {
+               bool x = true;
+
+               int a;
+               if (x ? OutCall (out a) : OutCall (out a))
+                       System.Console.WriteLine (a);
+               else
+                       System.Console.WriteLine (a);
        }
 
        static bool OutCall (out int arg)
index 55205a1608f2ada528758b8cdd6047c5a71aaf86..6242ebb7c44c75872fdc62178be14cfc961ebd03 100644 (file)
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
       </method>\r
+      <method name="Void Test8()" attrs="145">\r
+        <size>51</size>\r
+      </method>\r
     </type>\r
   </test>\r
   <test name="test-881.cs">\r