2005-05-31 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / mcs / ecore.cs
index f1c9984ca17a23a1b3ca8a44522466c9c5a8fca0..3f2940843e3ae562c7b81ba7804f87661772750c 100644 (file)
@@ -395,14 +395,14 @@ namespace Mono.CSharp {
                ///   Currently ResolveLValue wraps DoResolveLValue to perform sanity
                ///   checking and assertion checking on what we expect from Resolve
                /// </remarks>
-               public Expression ResolveLValue (EmitContext ec, Expression right_side)
+               public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
                {
                        int errors = Report.Errors;
                        Expression e = DoResolveLValue (ec, right_side);
 
                        if (e == null) {
                                if (errors == Report.Errors)
-                                       Report.Error (131, Location, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
+                                       Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
                                return null;
                        }
 
@@ -663,43 +663,47 @@ namespace Mono.CSharp {
                                                       Location loc)
                {
                        if (almostMatchedMembers.Count != 0) {
-                               if (qualifier_type == null) {
-                                       foreach (MemberInfo m in almostMatchedMembers)
+                               for (int i = 0; i < almostMatchedMembers.Count; ++i) {
+                                       MemberInfo m = (MemberInfo) almostMatchedMembers [i];
+                                       for (int j = 0; j < i; ++j) {
+                                               if (m == almostMatchedMembers [j]) {
+                                                       m = null;
+                                                       break;
+                                               }
+                                       }
+                                       if (m == null)
+                                               continue;
+                                       
+                                       Type declaring_type = m.DeclaringType;
+                                       
+                                       Report.SymbolRelatedToPreviousError (m);
+                                       if (qualifier_type == null) {
                                                Report.Error (38, loc, 
                                                              "Cannot access non-static member `{0}' via nested type `{1}'", 
                                                              TypeManager.GetFullNameSignature (m),
                                                              TypeManager.CSharpName (ec.ContainerType));
-                                       return;
-                               }
-
-                               if (qualifier_type != ec.ContainerType) {
-                                       // Although a derived class can access protected members of
-                                       // its base class it cannot do so through an instance of the
-                                       // base class (CS1540).  If the qualifier_type is a base of the
-                                       // ec.ContainerType and the lookup succeeds with the latter one,
-                                       // then we are in this situation.
-                                       for (int i = 0; i < almostMatchedMembers.Count; ++i) {
-                                               MemberInfo m = (MemberInfo) almostMatchedMembers [i];
-                                               for (int j = 0; j < i; ++j) {
-                                                       if (m == almostMatchedMembers [j]) {
-                                                               m = null;
-                                                               break;
-                                                       }
-                                               }
-                                               if (m == null)
-                                                       continue;
-
-                                               Report.SymbolRelatedToPreviousError (m);
+                                               
+                                       } else if (qualifier_type != ec.ContainerType &&
+                                                  TypeManager.IsNestedFamilyAccessible (ec.ContainerType, declaring_type)) {
+                                               // Although a derived class can access protected members of
+                                               // its base class it cannot do so through an instance of the
+                                               // base class (CS1540).  If the qualifier_type is a base of the
+                                               // ec.ContainerType and the lookup succeeds with the latter one,
+                                               // then we are in this situation.
                                                Report.Error (1540, loc, 
                                                              "Cannot access protected member `{0}' via a qualifier of type `{1}';"
                                                              + " the qualifier must be of type `{2}' (or derived from it)", 
                                                              TypeManager.GetFullNameSignature (m),
                                                              TypeManager.CSharpName (qualifier_type),
                                                              TypeManager.CSharpName (ec.ContainerType));
+                                       } else {
+                                               Report.Error (122, loc, 
+                                                             "'{0}' is inaccessible due to its protection level", 
+                                                             TypeManager.GetFullNameSignature (m));
                                        }
-                                       return;
                                }
                                almostMatchedMembers.Clear ();
+                               return;
                        }
 
                        object lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
@@ -1382,6 +1386,104 @@ namespace Mono.CSharp {
                        child.Emit (ec);
                }
        }
+       /// <summary>
+       ///     This is a numeric cast to a Decimal
+       /// </summary>
+       public class CastToDecimal : EmptyCast {
+
+               MethodInfo conversion_operator;
+
+               public CastToDecimal (EmitContext ec, Expression child)
+                       : this (ec, child, false)
+               {
+               }
+
+               public CastToDecimal (EmitContext ec, Expression child, bool find_explicit)
+                       : base (child, TypeManager.decimal_type)
+               {
+                       conversion_operator = GetConversionOperator (ec, find_explicit);
+
+                       if (conversion_operator == null)
+                               Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+               }
+
+               // Returns the implicit operator that converts from
+               // 'child.Type' to System.Decimal.
+               MethodInfo GetConversionOperator (EmitContext ec, bool find_explicit)
+               {
+                       string operator_name = "op_Implicit";
+
+                       if (find_explicit)
+                               operator_name = "op_Explicit";
+                       
+                       MethodGroupExpr opers = Expression.MethodLookup (
+                               ec, type, operator_name, loc) as MethodGroupExpr;
+
+                       if (opers == null)
+                               Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+                       
+                       foreach (MethodInfo oper in opers.Methods) {
+                               ParameterData pd = TypeManager.GetParameterData (oper);
+
+                               if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+                                       return oper;
+                       }
+
+                       return null;
+               }
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       child.Emit (ec);
+
+                       ig.Emit (OpCodes.Call, conversion_operator);
+               }
+       }
+       /// <summary>
+       ///     This is an explicit numeric cast from a Decimal
+       /// </summary>
+       public class CastFromDecimal : EmptyCast
+       {
+               MethodInfo conversion_operator;
+               public CastFromDecimal (EmitContext ec, Expression child, Type return_type)
+                       : base (child, return_type)
+               {
+                       if (child.Type != TypeManager.decimal_type)
+                               throw new InternalErrorException (
+                                       "The expected type is Decimal, instead it is " + child.Type.FullName);
+
+                       conversion_operator = GetConversionOperator (ec);
+                       if (conversion_operator == null)
+                               Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+               }
+
+               // Returns the explicit operator that converts from an
+               // express of type System.Decimal to 'type'.
+               MethodInfo GetConversionOperator (EmitContext ec)
+               {                               
+                       MethodGroupExpr opers = Expression.MethodLookup (
+                               ec, child.Type, "op_Explicit", loc) as MethodGroupExpr;
+
+                       if (opers == null)
+                               Convert.Error_CannotImplicitConversion (loc, child.Type, type);
+                       
+                       foreach (MethodInfo oper in opers.Methods) {
+                               ParameterData pd = TypeManager.GetParameterData (oper);
+
+                               if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
+                                       return oper;
+                       }
+
+                       return null;
+               }
+               public override void Emit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+                       child.Emit (ec);
+
+                       ig.Emit (OpCodes.Call, conversion_operator);
+               }
+       }
 
         //
        // We need to special case this since an empty cast of
@@ -1932,6 +2034,7 @@ namespace Mono.CSharp {
        /// </summary>
        public class SimpleName : Expression {
                public string Name;
+               bool in_transit;
 
                public SimpleName (string name, Location l)
                {
@@ -1988,6 +2091,10 @@ namespace Mono.CSharp {
 
                Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
                {
+                       if (in_transit)
+                               return null;
+                       in_transit = true;
+
                        Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
                        if (e == null)
                                return null;
@@ -2031,15 +2138,15 @@ namespace Mono.CSharp {
                                        var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
                                        
                                        if (right_side != null)
-                                               return var.ResolveLValue (ec, right_side);
+                                               return var.ResolveLValue (ec, right_side, loc);
                                        else
                                                return var.Resolve (ec);
                                }
 
-                               ParameterReference pref = current_block.GetParameterReference (Name, loc);
+                               ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
                                if (pref != null) {
                                        if (right_side != null)
-                                               return pref.ResolveLValue (ec, right_side);
+                                               return pref.ResolveLValue (ec, right_side, loc);
                                        else
                                                return pref.Resolve (ec);
                                }
@@ -2740,8 +2847,12 @@ namespace Mono.CSharp {
                                        return exp;
                                }
                        }
-                       
-                       // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
+
+                       //
+                       // Decimal constants cannot be encoded in the constant blob, and thus are marked
+                       // as IsInitOnly ('readonly' in C# parlance).  We get its value from the 
+                       // DecimalConstantAttribute metadata.
+                       //
                        if (FieldInfo.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) {
                                object[] attrs = FieldInfo.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
                                if (attrs.Length == 1)