2004-11-02 Ben Maurer <bmaurer@ximian.com>
[mono.git] / mcs / mcs / expression.cs
index c77a7a5782b6537fbc682e1bd5acfdcfe0583141..af1be64d86bcf0604f3389d24c92f1a71dbcae81 100755 (executable)
@@ -2138,6 +2138,10 @@ namespace Mono.CSharp {
                                    (other == TypeManager.int32_type) ||
                                    (other == TypeManager.int64_type))
                                        Error_OperatorAmbiguous (loc, oper, l, r);
+                               else {
+                                       left = ForceConversion (ec, left, TypeManager.uint64_type);
+                                       right = ForceConversion (ec, right, TypeManager.uint64_type);
+                               }
                                type = TypeManager.uint64_type;
                        } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
                                //
@@ -2305,14 +2309,12 @@ namespace Mono.CSharp {
                        Type l = left.Type;
                        Type r = right.Type;
 
-                       bool overload_failed = false;
-
                        //
                        // Special cases: string comapred to null
                        //
                        if (oper == Operator.Equality || oper == Operator.Inequality){
-                               if ((l == TypeManager.string_type && (right is NullLiteral)) ||
-                                   (r == TypeManager.string_type && (left is NullLiteral))){
+                               if ((!TypeManager.IsValueType (l) && (right is NullLiteral)) ||
+                                   (!TypeManager.IsValueType (r) && (left is NullLiteral))) {
                                        Type = TypeManager.bool_type;
                                        
                                        return this;
@@ -2357,8 +2359,6 @@ namespace Mono.CSharp {
                                                MethodInfo mi = (MethodInfo) method;
                                                
                                                return new BinaryMethod (mi.ReturnType, method, args);
-                                       } else {
-                                               overload_failed = true;
                                        }
                                }
                        }
@@ -2537,16 +2537,16 @@ namespace Mono.CSharp {
                                                if (r == l)
                                                        return new PointerArithmetic (
                                                                false, left, right, TypeManager.int64_type,
-                                                               loc);
+                                                               loc).Resolve (ec);
                                        } else {
                                                Expression t = Make32or64 (ec, right);
                                                if (t != null)
-                                                       return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc);
+                                                       return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
                                        }
                                } else if (r.IsPointer && oper == Operator.Addition){
                                        Expression t = Make32or64 (ec, left);
                                        if (t != null)
-                                               return new PointerArithmetic (true, right, t, r, loc);
+                                               return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
                                }
                        }
                        
@@ -2683,14 +2683,6 @@ namespace Mono.CSharp {
                                }
                        }
                        
-                       //
-                       // We are dealing with numbers
-                       //
-                       if (overload_failed){
-                               Error_OperatorCannotBeApplied ();
-                               return null;
-                       }
-
                        //
                        // This will leave left or right set to null if there is an error
                        //
@@ -3154,7 +3146,11 @@ namespace Mono.CSharp {
        public class StringConcat : Expression {
                ArrayList operands;
                bool invalid = false;
-               
+               bool emit_conv_done = false;
+               //
+               // Are we also concating objects?
+               //
+               bool is_strings_only = true;
                
                public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
                {
@@ -3208,30 +3204,30 @@ namespace Mono.CSharp {
                {
                        MethodInfo concat_method = null;
                        
-                       //
-                       // Are we also concating objects?
-                       //
-                       bool is_strings_only = true;
-                       
                        //
                        // Do conversion to arguments; check for strings only
                        //
-                       for (int i = 0; i < operands.Count; i ++) {
-                               Expression e = (Expression) operands [i];
-                               is_strings_only &= e.Type == TypeManager.string_type;
-                       }
                        
-                       for (int i = 0; i < operands.Count; i ++) {
-                               Expression e = (Expression) operands [i];
+                       // This can get called multiple times, so we have to deal with that.
+                       if (!emit_conv_done) {
+                               emit_conv_done = true;
+                               for (int i = 0; i < operands.Count; i ++) {
+                                       Expression e = (Expression) operands [i];
+                                       is_strings_only &= e.Type == TypeManager.string_type;
+                               }
                                
-                               if (! is_strings_only && e.Type == TypeManager.string_type) {
-                                       // need to make sure this is an object, because the EmitParams
-                                       // method might look at the type of this expression, see it is a
-                                       // string and emit a string [] when we want an object [];
+                               for (int i = 0; i < operands.Count; i ++) {
+                                       Expression e = (Expression) operands [i];
                                        
-                                       e = Convert.ImplicitConversion (ec, e, TypeManager.object_type, loc);
+                                       if (! is_strings_only && e.Type == TypeManager.string_type) {
+                                               // need to make sure this is an object, because the EmitParams
+                                               // method might look at the type of this expression, see it is a
+                                               // string and emit a string [] when we want an object [];
+                                               
+                                               e = new EmptyCast (e, TypeManager.object_type);
+                                       }
+                                       operands [i] = new Argument (e, Argument.AType.Expression);
                                }
-                               operands [i] = new Argument (e, Argument.AType.Expression);
                        }
                        
                        //
@@ -3418,7 +3414,6 @@ namespace Mono.CSharp {
                public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
                {
                        type = t;
-                       eclass = ExprClass.Variable;
                        this.loc = loc;
                        left = l;
                        right = r;
@@ -3427,9 +3422,13 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       //
-                       // We are born fully resolved
-                       //
+                       eclass = ExprClass.Variable;
+                       
+                       if (left.Type == TypeManager.void_ptr_type) {
+                               Error (242, "The operation in question is undefined on void pointers");
+                               return null;
+                       }
+                       
                        return this;
                }
 
@@ -3437,7 +3436,8 @@ namespace Mono.CSharp {
                {
                        Type op_type = left.Type;
                        ILGenerator ig = ec.ig;
-                       int size = GetTypeSize (TypeManager.GetElementType (op_type));
+                       Type element = TypeManager.GetElementType (op_type);
+                       int size = GetTypeSize (element);
                        Type rtype = right.Type;
                        
                        if (rtype.IsPointer){
@@ -3450,7 +3450,7 @@ namespace Mono.CSharp {
 
                                if (size != 1){
                                        if (size == 0)
-                                               ig.Emit (OpCodes.Sizeof, op_type);
+                                               ig.Emit (OpCodes.Sizeof, element);
                                        else 
                                                IntLiteral.EmitInt (ig, size);
                                        ig.Emit (OpCodes.Div);
@@ -3465,7 +3465,7 @@ namespace Mono.CSharp {
                                right.Emit (ec);
                                if (size != 1){
                                        if (size == 0)
-                                               ig.Emit (OpCodes.Sizeof, op_type);
+                                               ig.Emit (OpCodes.Sizeof, element);
                                        else 
                                                IntLiteral.EmitInt (ig, size);
                                        if (rtype == TypeManager.int64_type)
@@ -3473,8 +3473,11 @@ namespace Mono.CSharp {
                                        else if (rtype == TypeManager.uint64_type)
                                                ig.Emit (OpCodes.Conv_U8);
                                        ig.Emit (OpCodes.Mul);
-                                       ig.Emit (OpCodes.Conv_I);
                                }
+                               
+                               if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+                                       ig.Emit (OpCodes.Conv_I);
+                               
                                if (is_add)
                                        ig.Emit (OpCodes.Add);
                                else
@@ -3668,7 +3671,7 @@ namespace Mono.CSharp {
                        if (e != null) {
                                local_info.Used = true;
                                eclass = ExprClass.Value;
-                               return e;
+                               return e.Resolve (ec);
                        }
 
                        VariableInfo variable_info = local_info.VariableInfo; 
@@ -4233,85 +4236,6 @@ namespace Mono.CSharp {
                        if (argument_type == q)
                                return 0;
 
-                       //
-                       // Now probe whether an implicit constant expression conversion
-                       // can be used.
-                       //
-                       // An implicit constant expression conversion permits the following
-                       // conversions:
-                       //
-                       //    * A constant-expression of type `int' can be converted to type
-                       //      sbyte, byute, short, ushort, uint, ulong provided the value of
-                       //      of the expression is withing the range of the destination type.
-                       //
-                       //    * A constant-expression of type long can be converted to type
-                       //      ulong, provided the value of the constant expression is not negative
-                       //
-                       // FIXME: Note that this assumes that constant folding has
-                       // taken place.  We dont do constant folding yet.
-                       //
-
-                       if (argument_expr is IntConstant){
-                               IntConstant ei = (IntConstant) argument_expr;
-                               int value = ei.Value;
-
-                               if (p == TypeManager.sbyte_type){
-                                       if (value >= SByte.MinValue && value <= SByte.MaxValue)
-                                               return 1;
-                               } else if (p == TypeManager.byte_type){
-                                       if (q == TypeManager.sbyte_type &&
-                                           value >= SByte.MinValue && value <= SByte.MaxValue)
-                                               return 0;
-                                       else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
-                                               return 1;
-                               } else if (p == TypeManager.short_type){
-                                       if (value >= Int16.MinValue && value <= Int16.MaxValue)
-                                               return 1;
-                               } else if (p == TypeManager.ushort_type){
-                                       if (q == TypeManager.short_type &&
-                                           value >= Int16.MinValue && value <= Int16.MaxValue)
-                                               return 0;
-                                       else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
-                                               return 1;
-                               } else if (p == TypeManager.int32_type){
-                                       if (value >= Int32.MinValue && value <= Int32.MaxValue)
-                                               return 1;
-                               } else if (p == TypeManager.uint32_type){
-                                       //
-                                       // we can optimize this case: a positive int32
-                                       // always fits on a uint32
-                                       //
-                                       if (value >= 0)
-                                               return 1;
-                               } else if (p == TypeManager.uint64_type){
-                                       //
-                                       // we can optimize this case: a positive int32
-                                       // always fits on a uint64
-                                       //
-
-                                        //
-                                        // This special case is needed because csc behaves like this.
-                                        // int -> uint is better than int -> ulong!
-                                        //
-                                        if (q == TypeManager.uint32_type)
-                                                return 0;
-                                        
-                                       if (q == TypeManager.int64_type)
-                                               return 0;
-                                       else if (value >= 0)
-                                               return 1;
-                               } else if (p == TypeManager.int64_type){
-                                       return 1;
-                               }
-                       } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
-                               LongConstant lc = (LongConstant) argument_expr;
-                               
-                               if (p == TypeManager.uint64_type){
-                                       if (lc.Value > 0)
-                                               return 1;
-                               }
-                       }
-
                        if (q == null) {
                                Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
                                
@@ -4559,7 +4483,8 @@ namespace Mono.CSharp {
                ///   Determines if the candidate method, if a params method, is applicable
                ///   in its expanded form to the given set of arguments
                /// </summary>
-               static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
+               static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
+                                                     MethodBase candidate, bool do_varargs)
                {
                        int arg_count;
                        
@@ -4575,12 +4500,15 @@ namespace Mono.CSharp {
                                return false;
 
                        int count = pd_count - 1;
-
-                       bool is_varargs = false;
-                       if (pd.ParameterModifier (count) == Parameter.Modifier.ARGLIST)
-                               is_varargs = true;
-                       else if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
-                               return false;
+                       if (do_varargs) {
+                               if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
+                                       return false;
+                               if (pd_count != arg_count)
+                                       return false;
+                       } else {
+                               if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
+                                       return false;
+                       }
                        
                        if (count > arg_count)
                                return false;
@@ -4624,14 +4552,19 @@ namespace Mono.CSharp {
                                
                        }
 
-                       if (is_varargs)
+                       if (do_varargs) {
+                               Argument a = (Argument) arguments [count];
+                               if (!(a.Expr is Arglist))
+                                       return false;
+
                                return true;
+                       }
 
                        Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
 
                        for (int i = pd_count - 1; i < arg_count; i++) {
                                Argument a = (Argument) arguments [i];
-                               
+
                                if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
                                        return false;
                        }
@@ -4763,7 +4696,16 @@ namespace Mono.CSharp {
                                         candidates.Add (candidate);
                                         applicable_type = candidate.DeclaringType;
                                         found_applicable = true;
-                                } else if (IsParamsMethodApplicable (ec, Arguments, candidate)) {
+                                } else if (IsParamsMethodApplicable (ec, Arguments, candidate, false)) {
+                                       if (candidate_to_form == null)
+                                               candidate_to_form = new PtrHashtable ();
+                                       
+                                       // Candidate is applicable in expanded form
+                                       candidates.Add (candidate);
+                                       applicable_type = candidate.DeclaringType;
+                                       found_applicable = true; 
+                                       candidate_to_form [candidate] = candidate;
+                                } else if (IsParamsMethodApplicable (ec, Arguments, candidate, true)) {
                                        if (candidate_to_form == null)
                                                candidate_to_form = new PtrHashtable ();
                                        
@@ -5903,7 +5845,7 @@ namespace Mono.CSharp {
                                        Expression tmp = (Expression) o;
                                        tmp = tmp.Resolve (ec);
                                        if (tmp == null)
-                                               continue;
+                                               return false;
 
                                        // Console.WriteLine ("I got: " + tmp);
                                        // Handle initialization from vars, fields etc.
@@ -6077,10 +6019,12 @@ namespace Mono.CSharp {
 
                        if (type == null)
                                return false;
-
-                       underlying_type = type;
-                       if (underlying_type.IsArray)
-                               underlying_type = TypeManager.GetElementType (underlying_type);
+                       
+                       if (!type.IsArray) {
+                               Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
+                               return false;
+                       }
+                       underlying_type = TypeManager.GetElementType (type);
                        dimensions = type.GetArrayRank ();
 
                        return true;
@@ -6784,6 +6728,10 @@ namespace Mono.CSharp {
                                return null;
                        }
 
+                       if (typearg.IsPointer && !ec.InUnsafe){
+                               UnsafeError (loc);
+                               return null;
+                       }
                        CheckObsoleteAttribute (typearg);
 
                        type = TypeManager.type_type;
@@ -6897,7 +6845,7 @@ namespace Mono.CSharp {
                                      "type name instead");
                }
 
-               static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
+               public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
                {
                        SimpleName sn = left_original as SimpleName;
                        if (sn == null || left == null || left.Type.Name != sn.Name)
@@ -7108,7 +7056,7 @@ namespace Mono.CSharp {
                        //
 
                        Expression original = expr;
-                       expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
+                       expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
                        if (expr == null)
                                return null;
 
@@ -7418,7 +7366,7 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               Expression MakePointerAccess ()
+               Expression MakePointerAccess (EmitContext ec)
                {
                        Type t = Expr.Type;
 
@@ -7432,8 +7380,10 @@ namespace Mono.CSharp {
                        }
                        Expression p;
 
-                       p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
-                       return new Indirection (p, loc);
+                       p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
+                       if (p == null)
+                               return null;
+                       return new Indirection (p, loc).Resolve (ec);
                }
                
                public override Expression DoResolve (EmitContext ec)
@@ -7457,7 +7407,7 @@ namespace Mono.CSharp {
                        if (t.IsArray)
                                return (new ArrayAccess (this, loc)).Resolve (ec);
                        else if (t.IsPointer)
-                               return MakePointerAccess ();
+                               return MakePointerAccess (ec);
                        else
                                return (new IndexerAccess (this, loc)).Resolve (ec);
                }
@@ -7471,7 +7421,7 @@ namespace Mono.CSharp {
                        if (t.IsArray)
                                return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
                        else if (t.IsPointer)
-                               return MakePointerAccess ();
+                               return MakePointerAccess (ec);
                        else
                                return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
                }
@@ -7613,7 +7563,7 @@ namespace Mono.CSharp {
                        //Console.WriteLine (new System.Diagnostics.StackTrace ());
                        is_stobj = false;
                        t = TypeManager.TypeToCoreType (t);
-                       if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
+                       if (TypeManager.IsEnumType (t))
                                t = TypeManager.EnumToUnderlying (t);
                        if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
                            t == TypeManager.bool_type)
@@ -8193,6 +8143,9 @@ namespace Mono.CSharp {
 
                                pe.IsBase = true;
                        }
+                       
+                       if (e is MethodGroupExpr)
+                               ((MethodGroupExpr) e).IsBase = true;
 
                        return e;
                }
@@ -8479,6 +8432,14 @@ namespace Mono.CSharp {
                                        return null;
                        }
 
+                       Constant c = count as Constant;
+                       // TODO: because we don't have property IsNegative
+                       if (c != null && c.ConvertToUInt () == null) {
+                                // "Cannot use a negative size with stackalloc"
+                               Report.Error_T (247, loc);
+                               return null;
+                       }
+
                        if (ec.CurrentBranching.InCatch () ||
                            ec.CurrentBranching.InFinally (true)) {
                                Error (255,