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