2001-09-18 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / expression.cs
index 092494a7dda5ae597a39eab86f1ee686ea2aedca..08dfb19ccfb2bbf060ed35340f4555fec2b80257 100755 (executable)
@@ -98,7 +98,7 @@ namespace CIR {
                //
                // Return values:
                //     If the return value is an Array, then it is an array of
-               //     MethodInfos
+               //     MethodBases
                //   
                //     If the return value is an MemberInfo, it is anything, but a Method
                //
@@ -111,22 +111,10 @@ namespace CIR {
                //
                // This is so we can catch correctly attempts to invoke instance methods
                // from a static body (scan for error 120 in ResolveSimpleName).
-               // 
-               protected static Expression MemberLookup (RootContext rc, Type t, string name, bool same_type)
-               {
-                       MemberTypes mt =
-                               // MemberTypes.Constructor |
-                               MemberTypes.Event       |
-                               MemberTypes.Field       |
-                               MemberTypes.Method      |
-                               MemberTypes.NestedType  |
-                               MemberTypes.Property;
-                       
-                       BindingFlags bf =
-                               BindingFlags.Public |
-                               BindingFlags.Static |
-                               BindingFlags.Instance;
-                       
+               //
+               public static Expression MemberLookup (RootContext rc, Type t, string name,
+                                                         bool same_type, MemberTypes mt, BindingFlags bf)
+               {
                        if (same_type)
                                bf |= BindingFlags.NonPublic;
 
@@ -135,18 +123,46 @@ namespace CIR {
                        if (mi == null)
                                return null;
                        
-                       if (mi.Length == 1 && !(mi [0] is MethodInfo))
+                       if (mi.Length == 1 && !(mi [0] is MethodBase))
                                return Expression.ExprClassFromMemberInfo (mi [0]);
-
+                       
                        for (int i = 0; i < mi.Length; i++)
-                               if (!(mi [i] is MethodInfo)){
+                               if (!(mi [i] is MethodBase)){
                                        rc.Report.Error (-5, "Do not know how to reproduce this case: " + 
                                                         "Methods and non-Method with the same name, report this please");
-                                       
+
+                                       for (i = 0; i < mi.Length; i++){
+                                               Type tt = mi [i].GetType ();
+
+                                               Console.WriteLine (i + ": " + mi [i]);
+                                               while (tt != TypeManager.object_type){
+                                                       Console.WriteLine (tt);
+                                                       tt = tt.BaseType;
+                                               }
+                                       }
                                }
 
                        return new MethodGroupExpr (mi);
                }
+
+               public const MemberTypes AllMemberTypes =
+                       MemberTypes.Constructor |
+                       MemberTypes.Event       |
+                       MemberTypes.Field       |
+                       MemberTypes.Method      |
+                       MemberTypes.NestedType  |
+                       MemberTypes.Property;
+               
+               public const BindingFlags AllBindingsFlags =
+                       BindingFlags.Public |
+                       BindingFlags.Static |
+                       BindingFlags.Instance;
+
+               public static Expression MemberLookup (RootContext rc, Type t, string name,
+                                                         bool same_type)
+               {
+                       return MemberLookup (rc, t, name, same_type, AllMemberTypes, AllBindingsFlags);
+               }
                
                // <summary>
                //   Resolves the E in `E.I' side for a member_access
@@ -623,9 +639,9 @@ namespace CIR {
        public class Binary : Expression {
                public enum Operator {
                        Multiply, Divide, Modulo,
-                       Add, Substract,
+                       Add, Subtract,
                        ShiftLeft, ShiftRight,
-                       LessThan, GreatherThan, LessOrEqual, GreatherOrEqual, 
+                       LessThan, GreaterThan, LessOrEqual, GreaterOrEqual, 
                        Equal, NotEqual,
                        BitwiseAnd,
                        ExclusiveOr,
@@ -636,6 +652,9 @@ namespace CIR {
 
                Operator oper;
                Expression left, right;
+               MethodBase method;
+               ArrayList  Arguments;
+               
 
                public Binary (Operator oper, Expression left, Expression right)
                {
@@ -686,7 +705,7 @@ namespace CIR {
                                return "%";
                        case Operator.Add:
                                return "+";
-                       case Operator.Substract:
+                       case Operator.Subtract:
                                return "-";
                        case Operator.ShiftLeft:
                                return "<<";
@@ -694,11 +713,11 @@ namespace CIR {
                                return ">>";
                        case Operator.LessThan:
                                return "<";
-                       case Operator.GreatherThan:
+                       case Operator.GreaterThan:
                                return ">";
                        case Operator.LessOrEqual:
                                return "<=";
-                       case Operator.GreatherOrEqual:
+                       case Operator.GreaterOrEqual:
                                return ">=";
                        case Operator.Equal:
                                return "==";
@@ -822,6 +841,7 @@ namespace CIR {
                        } else {
                                left = ForceConversion (left, TypeManager.int32_type);
                                right = ForceConversion (right, TypeManager.int32_type);
+                               type = TypeManager.int32_type;
                        }
                }
 
@@ -868,12 +888,66 @@ namespace CIR {
                        //
                        // Step 1: Perform Operator Overload location
                        //
-
+                       Expression left_expr, right_expr;
                        
+                       string op = "Operator" + oper;
+
+                       left_expr = MemberLookup (tc.RootContext, l, op, false);
+
+                       if (!(left_expr is MethodGroupExpr)){
+                               // FIXME: Find proper error
+                               tc.RootContext.Report.Error (118, "Did find something that is not a method");
+                               return null;
+                       }
+
+                       right_expr = MemberLookup (tc.RootContext, r, op, false);
+
+                       if (!(right_expr is MethodGroupExpr)){
+                               // FIXME: Find proper error
+                               tc.RootContext.Report.Error (118, "Did find something that is not a method");
+                               return null;
+                       }
+
+                       if (left_expr != null || right_expr != null) {
+                               //
+                               // Now we need to form the union of these two sets and
+                               // then call OverloadResolve on that.
+                               //
+                               MethodGroupExpr left_set = null, right_set = null;
+                               int length1 = 0, length2 = 0;
+                               
+                               if (left_expr != null) {
+                                       left_set = (MethodGroupExpr) left_expr;
+                                       length1 = left_set.Methods.Length;
+                               }
+
+                               if (right_expr != null) {
+                                       right_set = (MethodGroupExpr) right_expr;
+                                       length2 = right_set.Methods.Length;
+                               }
+
+                               MemberInfo [] mi = new MemberInfo [length1 + length2];
+                               if (left_set != null)
+                                       left_set.Methods.CopyTo (mi, 0);
+                               if (right_set != null)
+                                       right_set.Methods.CopyTo (mi, length1);
+                               
+                               MethodGroupExpr union = new MethodGroupExpr (mi);
+                               
+                               Arguments = new ArrayList ();
+                               Arguments.Add (new Argument (left, Argument.AType.Expression));
+                               Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+                               method = Invocation.OverloadResolve (union, Arguments);
+                               if (method != null)
+                                       return this;
+
+                       }
+
                        //
                        // Step 2: Default operations on CLI native types.
                        //
-
+                       
                        // Only perform numeric promotions on:
                        // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
                        //
@@ -886,6 +960,9 @@ namespace CIR {
                        } else
                                DoNumericPromotions (tc, l, r);
 
+                       if (left == null || right == null)
+                               return null;
+
                        if (oper == Operator.BitwiseAnd ||
                            oper == Operator.BitwiseOr ||
                            oper == Operator.ExclusiveOr){
@@ -896,11 +973,17 @@ namespace CIR {
                                        error19 (tc);
                                        return null;
                                }
-                       } else 
-                       
-                       if (left == null || right == null)
-                               return null;
+                       }
 
+                       if (oper == Operator.Equal ||
+                           oper == Operator.NotEqual ||
+                           oper == Operator.LessOrEqual ||
+                           oper == Operator.LessThan ||
+                           oper == Operator.GreaterOrEqual ||
+                           oper == Operator.GreaterThan){
+                               type = TypeManager.bool_type;
+                       }
+                       
                        return this;
                }
                
@@ -911,7 +994,7 @@ namespace CIR {
 
                        if (left == null || right == null)
                                return null;
-                                       
+
                        return ResolveOperator (tc);
                }
 
@@ -920,9 +1003,9 @@ namespace CIR {
                        if (oper == Operator.Equal ||
                            oper == Operator.NotEqual ||
                            oper == Operator.LessThan ||
-                           oper == Operator.GreatherThan ||
+                           oper == Operator.GreaterThan ||
                            oper == Operator.LessOrEqual ||
-                           oper == Operator.GreatherOrEqual){
+                           oper == Operator.GreaterOrEqual){
                                return true;
                        } else
                                return false;
@@ -971,7 +1054,7 @@ namespace CIR {
                                        opcode = OpCodes.Blt;
                                break;
 
-                       case Operator.GreatherThan:
+                       case Operator.GreaterThan:
                                if (close_target)
                                        opcode = OpCodes.Bgt_S;
                                else
@@ -985,7 +1068,7 @@ namespace CIR {
                                        opcode = OpCodes.Ble;
                                break;
 
-                       case Operator.GreatherOrEqual:
+                       case Operator.GreaterOrEqual:
                                if (close_target)
                                        opcode = OpCodes.Bge_S;
                                else
@@ -1006,6 +1089,32 @@ namespace CIR {
                        Type l = left.Type;
                        Type r = right.Type;
                        OpCode opcode;
+
+                       if (method != null) {
+
+                               bool is_static = method.IsStatic;
+
+                               // FIXME : I am just not able to get this right !!
+                               // There's something wrong with this part which causes
+                               // an InvalidProgramException if this code is emitted
+                               
+                               //if (Arguments != null)
+                               //      Invocation.EmitArguments (ec, Arguments);
+                               
+                               //if (is_static){
+                               //      if (method is MethodInfo)
+                               //              ig.Emit (OpCodes.Call, (MethodInfo) method);
+                               //      else
+                               //              ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+                               //} else {
+                               //      if (method is MethodInfo)
+                               //              ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+                               //      else
+                               //              ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+                               //}
+                               
+                               //return;
+                       }
                        
                        left.Emit (ec);
                        right.Emit (ec);
@@ -1050,7 +1159,7 @@ namespace CIR {
                                        opcode = OpCodes.Add;
                                break;
 
-                       case Operator.Substract:
+                       case Operator.Subtract:
                                if (ec.CheckState){
                                        if (l == TypeManager.int32_type || l == TypeManager.int64_type)
                                                opcode = OpCodes.Sub_Ovf;
@@ -1085,7 +1194,7 @@ namespace CIR {
                                opcode = OpCodes.Clt;
                                break;
 
-                       case Operator.GreatherThan:
+                       case Operator.GreaterThan:
                                opcode = OpCodes.Cgt;
                                break;
 
@@ -1096,7 +1205,7 @@ namespace CIR {
                                opcode = OpCodes.Ceq;
                                break;
 
-                       case Operator.GreatherOrEqual:
+                       case Operator.GreaterOrEqual:
                                ec.ig.Emit (OpCodes.Clt);
                                ec.ig.Emit (OpCodes.Ldc_I4_1);
                                
@@ -1378,6 +1487,7 @@ namespace CIR {
                public bool Resolve (TypeContainer tc)
                {
                        expr = expr.Resolve (tc);
+
                        return expr != null;
                }
 
@@ -1393,9 +1503,14 @@ namespace CIR {
        public class Invocation : Expression {
                public readonly ArrayList Arguments;
                Expression expr;
-               MethodInfo method = null;
+               MethodBase method = null;
                
                static Hashtable method_parameter_cache;
+
+               static Invocation ()
+               {
+                       method_parameter_cache = new Hashtable ();
+               }
                        
                //
                // arguments is an ArrayList, but we do not want to typecast,
@@ -1427,27 +1542,34 @@ namespace CIR {
                /// </summary>
                static int Badness (Argument a, Type t)
                {
-                       Console.WriteLine ("Considering: " + t + " and " + a.Expr.Type); 
-                       if (t == a.Expr.Type)
+                       if (a.Expr.Type == null){
+                               throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
+                       }
+                       
+                       if (t == a.Expr.Type) 
                                return 0;
-
+                       
                        // FIXME: Implement implicit conversions here.
                        // FIXME: Implement better conversion here.
                        
                        return -1;
                }
 
-               static ParameterData GetParameterData (TypeContainer tc, MethodBase mb)
+               // <summary>
+               //   Returns the Parameters (a ParameterData interface) for the
+               //   Method `mb'
+               // </summary>
+               static ParameterData GetParameterData (MethodBase mb)
                {
                        object pd = method_parameter_cache [mb];
 
                        if (pd != null)
                                return (ParameterData) pd;
 
-                       if (mb is MethodBuilder){
-                               Method m = tc.LookupMethodByBuilder ((MethodBuilder) mb);
+                       if (mb is MethodBuilder || mb is ConstructorBuilder){
+                               MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
 
-                               InternalParameters ip = m.GetParameters ();
+                               InternalParameters ip = mc.ParameterInfo;
                                method_parameter_cache [mb] = ip;
 
                                return (ParameterData) ip;
@@ -1462,33 +1584,53 @@ namespace CIR {
                
                // <summary>
                //   Find the Applicable Function Members (7.4.2.1)
+               //
+               //   me: Method Group expression with the members to select.
+               //       it might contain constructors or methods (or anything
+               //       that maps to a method).
+               //
+               //   Arguments: ArrayList containing resolved Argument objects.
+               //
+               //   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+               //            that is the best match of me on Arguments.
+               //
                // </summary>
-               static MethodInfo OverloadResolve (TypeContainer tc, MethodGroupExpr me, ArrayList Arguments)
+               public static MethodBase OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
                {
                        ArrayList afm = new ArrayList ();
                        int best_match = 10000;
                        int best_match_idx = -1;
-                       MethodInfo method = null;
-                       
+                       MethodBase method = null;
+                       int argument_count;
+
+                       if (Arguments == null)
+                               argument_count = 0;
+                       else
+                               argument_count = Arguments.Count;
+
                        for (int i = me.Methods.Length; i > 0; ){
                                i--;
                                MethodBase mb = me.Methods [i];
                                ParameterData pd;
 
-                               pd = GetParameterData (tc, mb);
+                               pd = GetParameterData (mb);
+
+                               // If this is the case, we have a method with no args - presumably
+                               if (pd == null && argument_count == 0)
+                                       return me.Methods [0];
 
                                //
                                // Compute how good this is
                                //
-                               if (pd.Count == Arguments.Count){
+                               if (pd.Count == argument_count){
                                        int badness = 0;
                                        
-                                       for (int j = Arguments.Count; j > 0;){
+                                       for (int j = argument_count; j > 0;){
                                                int x;
                                                j--;
                                                
                                                Argument a = (Argument) Arguments [j];
-                                               
+
                                                x = Badness (a, pd.ParameterType (j));
                                                
                                                if (x < 0){
@@ -1526,13 +1668,10 @@ namespace CIR {
 
                        if (!(this.expr is MethodGroupExpr)){
                                tc.RootContext.Report.Error (118,
-                                      "Denotes an " + this.expr.ExprClass + " while a method was expected");
+                                      "Denotes a non-method (Detail: ExprClass=" + this.expr.ExprClass+")");
                                return null;
                        }
 
-                       if (method_parameter_cache == null)
-                               method_parameter_cache = new Hashtable ();
-
                        //
                        // Next, evaluate all the expressions in the argument list
                        //
@@ -1546,7 +1685,7 @@ namespace CIR {
                                }
                        }
 
-                       method = OverloadResolve (tc, (MethodGroupExpr) this.expr, Arguments);
+                       method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
 
                        if (method == null){
                                tc.RootContext.Report.Error (-6,
@@ -1554,20 +1693,57 @@ namespace CIR {
                                return null;
                        }
 
+                       if (method is MethodInfo)
+                               type = ((MethodInfo)method).ReturnType;
+
                        return this;
                }
 
-               public override void Emit (EmitContext ec)
+               public static void EmitArguments (EmitContext ec, ArrayList Arguments)
                {
-                       int top = Arguments.Count;
+                       int top;
+
+                       if (Arguments != null)
+                               top = Arguments.Count;
+                       else
+                               top = 0;
 
                        for (int i = 0; i < top; i++){
                                Argument a = (Argument) Arguments [i];
 
                                a.Emit (ec);
                        }
+               }
+               
+               public override void Emit (EmitContext ec)
+               {
+                       bool is_static = method.IsStatic;
+
+                       if (!is_static){
+                               MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+
+                               if (mg.InstanceExpression == null){
+                                       Console.WriteLine ("Internal compiler error.  Should check in the method groups for static/instance");
+                               }
+
+                               mg.InstanceExpression.Emit (ec);
+                       }
+
+                       if (Arguments != null)
+                               EmitArguments (ec, Arguments);
+
+                       if (is_static){
+                               if (method is MethodInfo)
+                                       ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
+                               else
+                                       ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+                       } else {
+                               if (method is MethodInfo)
+                                       ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+                               else
+                                       ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+                       } 
 
-                       ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
                }
        }
 
@@ -1586,6 +1762,7 @@ namespace CIR {
                public readonly ArrayList Indices;
                public readonly ArrayList Initializers;
                
+               MethodBase method = null;
 
                public New (string requested_type, ArrayList arguments)
                {
@@ -1605,12 +1782,49 @@ namespace CIR {
                
                public override Expression Resolve (TypeContainer tc)
                {
-                       // FIXME: Implement;
+                       type = tc.LookupType (RequestedType, false);
+
+                       if (type == null)
+                               return null;
+
+                       Expression ml;
+
+                       ml = MemberLookup (tc.RootContext, type, ".ctor", false,
+                                          MemberTypes.Constructor, AllBindingsFlags);
+
+                       if (! (ml is MethodGroupExpr)){
+                               //
+                               // FIXME: Find proper error
+                               //
+                               tc.RootContext.Report.Error (118, "Did find something that is not a method");
+                               return null;
+                       }
+                       
+                       if (Arguments != null){
+                               for (int i = Arguments.Count; i > 0;){
+                                       --i;
+                                       Argument a = (Argument) Arguments [i];
+
+                                       if (!a.Resolve (tc))
+                                               return null;
+                               }
+                       }
+
+                       method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments);
+
+                       if (method == null) {
+                               tc.RootContext.Report.Error (-6,
+                               "New invocation: Can not find a constructor for this argument list");
+                               return null;
+                       }
+
                        return this;
                }
 
                public override void Emit (EmitContext ec)
                {
+                       Invocation.EmitArguments (ec, Arguments);
+                       ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
                }
        }
 
@@ -1667,6 +1881,7 @@ namespace CIR {
        public class MemberAccess : Expression {
                public readonly string Identifier;
                Expression expr;
+               Expression member_lookup;
                
                public MemberAccess (Expression expr, string id)
                {
@@ -1682,8 +1897,37 @@ namespace CIR {
                
                public override Expression Resolve (TypeContainer tc)
                {
-                       // FIXME: Implement;
-                       return this;
+                       Expression new_expression = expr.Resolve (tc);
+
+                       if (new_expression == null)
+                               return null;
+
+                       Console.WriteLine ("This is what I figured: " + expr.Type + "/" + expr.ExprClass);
+
+                       member_lookup = MemberLookup (tc.RootContext, expr.Type, Identifier, false);
+
+                       if (member_lookup is MethodGroupExpr){
+                               MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
+
+                               //
+                               // Bind the instance expression to it
+                               //
+                               // FIXME: This is a horrible way of detecting if it is
+                               // an instance expression.  Figure out how to fix this.
+                               //
+                               Console.WriteLine ("FIXME: Horrible way of figuring if something is an isntance");
+
+                               if (expr is LocalVariableReference)
+                                       mg.InstanceExpression = expr;
+                                       
+                               return member_lookup;
+                       } else
+                               //
+                               // FIXME: This should generate the proper node
+                               // ie, for a Property Access, it should like call it
+                               // and stuff.
+
+                               return null;
                }
 
                public override void Emit (EmitContext ec)
@@ -1740,18 +1984,34 @@ namespace CIR {
        }
 
        // <summary>
-       //   Fully resolved expression that evaluates to a type
+       //   MethodGroup Expression.
+       //  
+       //   This is a fully resolved expression that evaluates to a type
        // </summary>
        public class MethodGroupExpr : Expression {
-               public readonly MethodInfo [] Methods;
+               public readonly MethodBase [] Methods;
+               Expression instance_expression = null;
                
                public MethodGroupExpr (MemberInfo [] mi)
                {
-                       Methods = new MethodInfo [mi.Length];
+                       Methods = new MethodBase [mi.Length];
                        mi.CopyTo (Methods, 0);
                        eclass = ExprClass.MethodGroup;
                }
 
+               //
+               // `A method group may have associated an instance expression' 
+               // 
+               public Expression InstanceExpression {
+                       get {
+                               return instance_expression;
+                       }
+
+                       set {
+                               instance_expression = value;
+                       }
+               }
+               
                override public Expression Resolve (TypeContainer tc)
                {
                        return this;
@@ -1795,6 +2055,7 @@ namespace CIR {
                {
                        FieldInfo = fi;
                        eclass = ExprClass.Variable;
+                       type = fi.FieldType;
                }
 
                override public Expression Resolve (TypeContainer tc)
@@ -1822,11 +2083,13 @@ namespace CIR {
                        eclass = ExprClass.PropertyAccess;
                        IsStatic = false;
                                
-                       MethodInfo [] acc = pi.GetAccessors ();
+                       MethodBase [] acc = pi.GetAccessors ();
 
                        for (int i = 0; i < acc.Length; i++)
                                if (acc [i].IsStatic)
                                        IsStatic = true;
+
+                       type = pi.PropertyType;
                }
 
                override public Expression Resolve (TypeContainer tc)
@@ -1906,12 +2169,12 @@ namespace CIR {
                }
                
        }
-
-               public class ElementAccess : Expression {
-
+       
+       public class ElementAccess : Expression {
+               
                public readonly ArrayList  Arguments;
                public readonly Expression Expr;
-
+               
                public ElementAccess (Expression e, ArrayList e_list)
                {
                        Expr = e;
@@ -1923,14 +2186,14 @@ namespace CIR {
                        // FIXME : Implement
                        return this;
                }
-
+               
                public override void Emit (EmitContext ec)
                {
                        // FIXME : Implement !
                }
-
+               
        }
-
+       
        public class BaseAccess : Expression {
 
                public enum BaseAccessType {