Author: martin
Date: 2006-06-15 17:58:26 -0400 (Thu, 15 Jun 2006)
New Revision: 61777

Added:
   trunk/mcs/tests/gtest-269.cs
   trunk/mcs/tests/gtest-270.cs
Modified:
   trunk/mcs/gmcs/ChangeLog
   trunk/mcs/gmcs/statement.cs
Log:
2006-06-15  Martin Baulig  <[EMAIL PROTECTED]>

        * statement.cs
        (SwitchLabel.ResolveAndReduce): Added `bool allow_nullable'
        argument; always allow a `null' label if true.
        (Switch.SwitchGoverningType): Take an `Expression expr' argument.
        (Switch.TableSwitchEmit, Switch.SimpleSwitchEmit): Check whether
        we have a `null' label and mark the new `null_target' label;
        default to the `default' label.
        (Switch.Resolve): Add support for nullable types.  Fixes #78630.



Modified: trunk/mcs/gmcs/ChangeLog
===================================================================
--- trunk/mcs/gmcs/ChangeLog    2006-06-15 21:54:41 UTC (rev 61776)
+++ trunk/mcs/gmcs/ChangeLog    2006-06-15 21:58:26 UTC (rev 61777)
@@ -1,5 +1,16 @@
 2006-06-15  Martin Baulig  <[EMAIL PROTECTED]>
 
+       * statement.cs
+       (SwitchLabel.ResolveAndReduce): Added `bool allow_nullable'
+       argument; always allow a `null' label if true.
+       (Switch.SwitchGoverningType): Take an `Expression expr' argument.
+       (Switch.TableSwitchEmit, Switch.SimpleSwitchEmit): Check whether
+       we have a `null' label and mark the new `null_target' label;
+       default to the `default' label.
+       (Switch.Resolve): Add support for nullable types.  Fixes #78630.
+
+2006-06-15  Martin Baulig  <[EMAIL PROTECTED]>
+
        * class.cs (Operator.Define): Allow an implicit/explicit operator
        to convert to/from a nullable value of the enclosing type.
 

Modified: trunk/mcs/gmcs/statement.cs
===================================================================
--- trunk/mcs/gmcs/statement.cs 2006-06-15 21:54:41 UTC (rev 61776)
+++ trunk/mcs/gmcs/statement.cs 2006-06-15 21:58:26 UTC (rev 61777)
@@ -2346,7 +2346,7 @@
                // Resolves the expression, reduces it to a literal if possible
                // and then converts it to the requested type.
                //
-               public bool ResolveAndReduce (EmitContext ec, Type 
required_type)
+               public bool ResolveAndReduce (EmitContext ec, Type 
required_type, bool allow_nullable)
                {       
                        Expression e = label.Resolve (ec);
 
@@ -2364,6 +2364,11 @@
                                return true;
                        }
 
+                       if (allow_nullable && c.GetValue () == null) {
+                               converted = NullStringCase;
+                               return true;
+                       }
+
                        c = c.ToType (required_type, loc);
                        if (c == null)
                                return false;
@@ -2416,7 +2421,9 @@
                // Computed
                //
                Label default_target;
+               Label null_target;
                Expression new_expr;
+               Nullable.Unwrap unwrap;
                bool is_constant;
                SwitchSection constant_section;
                SwitchSection default_section;
@@ -2452,8 +2459,10 @@
                // expression that includes any potential conversions to the
                // integral types or to string.
                //
-               Expression SwitchGoverningType (EmitContext ec, Type t)
+               Expression SwitchGoverningType (EmitContext ec, Expression expr)
                {
+                       Type t = expr.Type;
+
                        if (t == TypeManager.byte_type ||
                            t == TypeManager.sbyte_type ||
                            t == TypeManager.ushort_type ||
@@ -2466,7 +2475,7 @@
                            t == TypeManager.string_type ||
                            t == TypeManager.bool_type ||
                            t.IsSubclassOf (TypeManager.enum_type))
-                               return Expr;
+                               return expr;
 
                        if (allowed_types == null){
                                allowed_types = new Type [] {
@@ -2494,7 +2503,7 @@
                        foreach (Type tt in allowed_types){
                                Expression e;
                                
-                               e = Convert.ImplicitUserConversion (ec, Expr, 
tt, loc);
+                               e = Convert.ImplicitUserConversion (ec, expr, 
tt, loc);
                                if (e == null)
                                        continue;
 
@@ -2509,7 +2518,7 @@
                                        Report.ExtraInformation (
                                                loc,
                                                String.Format ("reason: more 
than one conversion to an integral type exist for type {0}",
-                                                              
TypeManager.CSharpName (Expr.Type)));
+                                                              
TypeManager.CSharpName (expr.Type)));
                                        return null;
                                }
 
@@ -2543,7 +2552,7 @@
                                                continue;
                                        }
 
-                                       if (!sl.ResolveAndReduce (ec, 
SwitchType)){
+                                       if (!sl.ResolveAndReduce (ec, 
SwitchType, unwrap != null)){
                                                error = true;
                                                continue;
                                        }
@@ -2551,11 +2560,10 @@
                                        object key = sl.Converted;
                                        try {
                                                Elements.Add (key, sl);
+                                       } catch (ArgumentException) {
+                                               sl.Erorr_AlreadyOccurs ();
+                                               error = true;
                                        }
-                                       catch (ArgumentException) {
-                                                sl.Erorr_AlreadyOccurs ();
-                                                error = true;
-                                        }
                                }
                        }
                        return !error;
@@ -2819,16 +2827,27 @@
 
                        // now emit the code for the sections
                        bool fFoundDefault = false;
+                       bool fFoundNull = false;
                        foreach (SwitchSection ss in Sections)
                        {
                                foreach (SwitchLabel sl in ss.Labels)
+                                       if (sl.Converted == 
SwitchLabel.NullStringCase)
+                                               fFoundNull = true;
+                       }
+
+                       foreach (SwitchSection ss in Sections)
+                       {
+                               foreach (SwitchLabel sl in ss.Labels)
                                {
                                        ig.MarkLabel (sl.GetILLabel (ec));
                                        ig.MarkLabel (sl.GetILLabelCode (ec));
-                                       if (sl.Label == null)
-                                       {
+                                       if (sl.Converted == 
SwitchLabel.NullStringCase)
+                                               ig.MarkLabel (null_target);
+                                       else if (sl.Label == null) {
                                                ig.MarkLabel (lblDefault);
                                                fFoundDefault = true;
+                                               if (!fFoundNull)
+                                                       ig.MarkLabel 
(null_target);
                                        }
                                }
                                ss.Block.Emit (ec);
@@ -2851,7 +2870,6 @@
                        ILGenerator ig = ec.ig;
                        Label end_of_switch = ig.DefineLabel ();
                        Label next_test = ig.DefineLabel ();
-                       Label null_target = ig.DefineLabel ();
                        bool first_test = true;
                        bool pending_goto_end = false;
                        bool null_marked = false;
@@ -2956,7 +2974,16 @@
                        if (Expr == null)
                                return false;
 
-                       new_expr = SwitchGoverningType (ec, Expr.Type);
+                       new_expr = SwitchGoverningType (ec, Expr);
+
+                       if ((new_expr == null) && TypeManager.IsNullableType 
(Expr.Type)) {
+                               unwrap = new Nullable.Unwrap (Expr, 
loc).Resolve (ec) as Nullable.Unwrap;
+                               if (unwrap == null)
+                                       return false;
+
+                               new_expr = SwitchGoverningType (ec, unwrap);
+                       }
+
                        if (new_expr == null){
                                Report.Error (151, loc, "A value of an integral 
type or string expected for switch");
                                return false;
@@ -2968,6 +2995,10 @@
                        if (!CheckSwitch (ec))
                                return false;
 
+                       if (unwrap != null) {
+                               Elements.Remove (SwitchLabel.NullStringCase);
+                       }
+
                        Switch old_switch = ec.Switch;
                        ec.Switch = this;
                        ec.Switch.SwitchType = SwitchType;
@@ -3023,17 +3054,24 @@
                {
                        ILGenerator ig = ec.ig;
 
+                       default_target = ig.DefineLabel ();
+                       null_target = ig.DefineLabel ();
+
                        // Store variable for comparission purposes
                        LocalBuilder value;
-                       if (!is_constant) {
+                       if (unwrap != null) {
                                value = ig.DeclareLocal (SwitchType);
-                       new_expr.Emit (ec);
+                               unwrap.EmitCheck (ec);
+                               ig.Emit (OpCodes.Brfalse, null_target);
+                               new_expr.Emit (ec);
                                ig.Emit (OpCodes.Stloc, value);
+                       } else if (!is_constant) {
+                               value = ig.DeclareLocal (SwitchType);
+                               new_expr.Emit (ec);
+                               ig.Emit (OpCodes.Stloc, value);
                        } else
                                value = null;
 
-                       default_target = ig.DefineLabel ();
-
                        //
                        // Setup the codegen context
                        //

Added: trunk/mcs/tests/gtest-269.cs
===================================================================
--- trunk/mcs/tests/gtest-269.cs        2006-06-15 21:54:41 UTC (rev 61776)
+++ trunk/mcs/tests/gtest-269.cs        2006-06-15 21:58:26 UTC (rev 61777)
@@ -0,0 +1,134 @@
+using System;
+
+[Flags]
+enum IrishBeer {
+       Stout           = 0x1000,
+       Ale             = 0x2000,
+       Lager           = 0x3000,
+
+       Guinness        = 1 | Stout,
+       Smithwicks      = 2 | Ale
+}
+
+struct IrishPub
+{
+       public readonly IrishBeer Beer;
+
+       public IrishPub (IrishBeer beer)
+       {
+               this.Beer = beer;
+       }
+
+       public static implicit operator long (IrishPub? pub)
+       {
+               return pub.HasValue ? (long) pub.Value.Beer : 0;
+       }
+
+       public static implicit operator IrishPub? (long value)
+       {
+               return new IrishPub ((IrishBeer) value);
+       }
+}
+
+class X
+{
+       static int Beer (IrishPub? pub)
+       {
+               switch (pub) {
+               case 0x1001:
+                       return 1;
+
+               case 0x2002:
+                       return 2;
+
+               default:
+                       return 3;
+               }
+       }
+
+       static long PubToLong (IrishPub pub)
+       {
+               return pub;
+       }
+
+       static int Test (int? a)
+       {
+               switch (a) {
+               case 0:
+                       return 0;
+
+               case 3:
+                       return 1;
+
+               default:
+                       return 2;
+               }
+       }
+
+       static int TestWithNull (int? a)
+       {
+               switch (a) {
+               case 0:
+                       return 0;
+
+               case 3:
+                       return 1;
+
+               case null:
+                       return 2;
+
+               default:
+                       return 3;
+               }
+       }
+
+       static long? Foo (bool flag)
+       {
+               if (flag)
+                       return 4;
+               else
+                       return null;
+       }
+
+       static int Test (bool flag)
+       {
+               switch (Foo (flag)) {
+               case 0:
+                       return 0;
+
+               case 4:
+                       return 1;
+
+               default:
+                       return 2;
+               }
+       }
+
+       static int Main ()
+       {
+               IrishPub pub = new IrishPub (IrishBeer.Guinness);
+               if (PubToLong (pub) != 0x1001)
+                       return 1;
+
+               if (Beer (null) != 3)
+                       return 2;
+               if (Beer (new IrishPub (IrishBeer.Guinness)) != 1)
+                       return 3;
+
+               if (Test (null) != 2)
+                       return 4;
+               if (Test (3) != 1)
+                       return 5;
+               if (Test (true) != 1)
+                       return 6;
+               if (Test (false) != 2)
+                       return 7;
+
+               if (TestWithNull (null) != 2)
+                       return 8;
+               if (TestWithNull (3) != 1)
+                       return 9;
+
+               return 0;
+       }
+}


Property changes on: trunk/mcs/tests/gtest-269.cs
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/mcs/tests/gtest-270.cs
===================================================================
--- trunk/mcs/tests/gtest-270.cs        2006-06-15 21:54:41 UTC (rev 61776)
+++ trunk/mcs/tests/gtest-270.cs        2006-06-15 21:58:26 UTC (rev 61777)
@@ -0,0 +1,27 @@
+using System;
+
+class X
+{
+       static int Test (int? a)
+       {
+               switch (a) {
+               case 0:
+                       return 0;
+               case 1:
+                       return 1;
+
+               default:
+                       return -1;
+               }
+       }
+
+       static int Main ()
+       {
+               if (Test (null) != -1)
+                       return 1;
+               if (Test (0) != 0)
+                       return 2;
+
+               return 0;
+       }
+}

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to