2003-04-19 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / ecore.cs
index 98817cfbcee51787176e9ea423312aa0b0a590bc..46a3c677a1a5e01ad9ecd576180fd6d508ca82b8 100755 (executable)
@@ -171,17 +171,6 @@ namespace Mono.CSharp {
                }
        }
 
-       /// <summary>
-       ///   Expression which resolves to a type.
-       /// </summary>
-       public interface ITypeExpression
-       {
-               /// <summary>
-               ///   Resolve the expression, but only lookup types.
-               /// </summary>
-               Expression DoResolveType (EmitContext ec);
-       }
-
        /// <remarks>
        ///   Base class for expressions
        /// </remarks>
@@ -278,7 +267,33 @@ namespace Mono.CSharp {
                {
                        return DoResolve (ec);
                }
-               
+
+               //
+               // This is used if the expression should be resolved as a type.
+               // the default implementation fails.   Use this method in
+               // those participants in the SimpleName chain system.
+               //
+               public virtual Expression ResolveAsTypeStep (EmitContext ec)
+               {
+                       return null;
+               }
+
+               //
+               // This is used to resolve the expression as a type, a null
+               // value will be returned if the expression is not a type
+               // reference
+               //
+               public Expression ResolveAsTypeTerminal (EmitContext ec)
+               {
+                       Expression e = ResolveAsTypeStep (ec);
+
+                       if (e == null)
+                               return null;
+                       if (e is SimpleName)
+                               return null;
+                       return e;
+               }
+              
                /// <summary>
                ///   Resolves an expression and performs semantic analysis on it.
                /// </summary>
@@ -289,15 +304,8 @@ namespace Mono.CSharp {
                /// </remarks>
                public Expression Resolve (EmitContext ec, ResolveFlags flags)
                {
-                       // Are we doing a types-only search ?
-                       if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) {
-                               ITypeExpression type_expr = this as ITypeExpression;
-
-                               if (type_expr == null)
-                                       return null;
-
-                               return type_expr.DoResolveType (ec);
-                       }
+                       if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) 
+                               return ResolveAsTypeStep (ec);
 
                        bool old_do_flow_analysis = ec.DoFlowAnalysis;
                        if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
@@ -328,7 +336,7 @@ namespace Mono.CSharp {
 
                        if ((e is TypeExpr) || (e is ComposedCast)) {
                                if ((flags & ResolveFlags.Type) == 0) {
-                                       e.Error118 (flags);
+                                       e.Error_UnexpectedKind (flags);
                                        return null;
                                }
 
@@ -338,7 +346,7 @@ namespace Mono.CSharp {
                        switch (e.eclass) {
                        case ExprClass.Type:
                                if ((flags & ResolveFlags.VariableOrValue) == 0) {
-                                       e.Error118 (flags);
+                                       e.Error_UnexpectedKind (flags);
                                        return null;
                                }
                                break;
@@ -356,7 +364,12 @@ namespace Mono.CSharp {
                        case ExprClass.EventAccess:
                        case ExprClass.IndexerAccess:
                                if ((flags & ResolveFlags.VariableOrValue) == 0) {
-                                       e.Error118 (flags);
+                                       Console.WriteLine ("I got: {0} and {1}", e.GetType (), e);
+                                       Console.WriteLine ("I am {0} and {1}", this.GetType (), this);
+                                       FieldInfo fi = ((FieldExpr) e).FieldInfo;
+                                       
+                                       Console.WriteLine ("{0} and {1}", fi.DeclaringType, fi.Name);
+                                       e.Error_UnexpectedKind (flags);
                                        return null;
                                }
                                break;
@@ -561,12 +574,12 @@ namespace Mono.CSharp {
 
                        int count = mi.Length;
 
-                       if (count > 1)
-                               return new MethodGroupExpr (mi, loc);
-
                        if (mi [0] is MethodBase)
                                return new MethodGroupExpr (mi, loc);
 
+                       if (count > 1)
+                               return null;
+
                        return ExprClassFromMemberInfo (ec, mi [0], loc);
                }
 
@@ -716,17 +729,22 @@ namespace Mono.CSharp {
                        // notice that it is possible to write "ValueType v = 1", the ValueType here
                        // is an abstract class, and not really a value type, so we apply the same rules.
                        //
-                       if (target_type == TypeManager.object_type || target_type == TypeManager.value_type) {
+                       if (target_type == TypeManager.object_type) {
                                //
                                // A pointer type cannot be converted to object
                                // 
                                if (expr_type.IsPointer)
                                        return null;
 
-                               if (TypeManager.IsValueType (expr_type))
+                               if (expr_type.IsValueType)
                                        return new BoxedCast (expr);
                                if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type)
                                        return new EmptyCast (expr, target_type);
+                       } else if (target_type == TypeManager.value_type) {
+                               if (expr_type.IsValueType)
+                                       return new BoxedCast (expr);
+                               if (expr is NullLiteral)
+                                       return new BoxedCast (expr);
                        } else if (expr_type.IsSubclassOf (target_type)) {
                                //
                                // Special case: enumeration to System.Enum.
@@ -735,7 +753,7 @@ namespace Mono.CSharp {
                                //
                                if (expr_type.IsEnum)
                                        return new BoxedCast (expr);
-                       
+
                                return new EmptyCast (expr, target_type);
                        } else {
 
@@ -746,7 +764,7 @@ namespace Mono.CSharp {
                                
                                // from the null type to any reference-type.
                                if (expr is NullLiteral && !target_type.IsValueType)
-                                       return new EmptyCast (expr, target_type);
+                                       return new NullLiteralTyped (target_type);
 
                                // from any class-type S to any interface-type T.
                                if (target_type.IsInterface) {
@@ -824,24 +842,27 @@ namespace Mono.CSharp {
                        //
                        // Attempt to do the implicit constant expression conversions
 
-                       if (expr is IntConstant){
-                               Expression e;
+                       if (expr is Constant){
                                
-                               e = TryImplicitIntConversion (target_type, (IntConstant) expr);
-
-                               if (e != null)
-                                       return e;
-                       } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
-                               //
-                               // Try the implicit constant expression conversion
-                               // from long to ulong, instead of a nice routine,
-                               // we just inline it
-                               //
-                               long v = ((LongConstant) expr).Value;
-                               if (v > 0)
-                                       return new ULongConstant ((ulong) v);
+                               if (expr is IntConstant){
+                                       Expression e;
+                                       
+                                       e = TryImplicitIntConversion (target_type, (IntConstant) expr);
+                                       
+                                       if (e != null)
+                                               return e;
+                               } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
+                                       //
+                                       // Try the implicit constant expression conversion
+                                       // from long to ulong, instead of a nice routine,
+                                       // we just inline it
+                                       //
+                                       long v = ((LongConstant) expr).Value;
+                                       if (v > 0)
+                                               return new ULongConstant ((ulong) v);
+                               } 
                        }
-
+                       
                        Type real_target_type = target_type;
 
                        if (expr_type == TypeManager.sbyte_type){
@@ -986,7 +1007,7 @@ namespace Mono.CSharp {
                        // This is the boxed case.
                        //
                        if (target_type == TypeManager.object_type) {
-                               if (expr_type.IsClass || TypeManager.IsValueType (expr_type) ||
+                               if (expr_type.IsClass || expr_type.IsValueType ||
                                    expr_type.IsInterface || expr_type == TypeManager.enum_type)
                                        return true;
                        } else if (expr_type.IsSubclassOf (target_type)) {
@@ -1501,6 +1522,60 @@ namespace Mono.CSharp {
                        return UserDefinedConversion (ec, source, target, loc, true);
                }
 
+               /// <summary>
+               ///   Returns an expression that can be used to invoke operator true
+               ///   on the expression if it exists.
+               /// </summary>
+               static public StaticCallExpr GetOperatorTrue (EmitContext ec, Expression e, Location loc)
+               {
+                       MethodBase method;
+                       Expression operator_group;
+
+                       operator_group = MethodLookup (ec, e.Type, "op_True", loc);
+                       if (operator_group == null)
+                               return null;
+
+                       ArrayList arguments = new ArrayList ();
+                       arguments.Add (new Argument (e, Argument.AType.Expression));
+                       method = Invocation.OverloadResolve (ec, (MethodGroupExpr) operator_group, arguments, loc);
+
+                       if (method == null)
+                               return null;
+
+                       return new StaticCallExpr ((MethodInfo) method, arguments, loc);
+               }
+
+               /// <summary>
+               ///   Resolves the expression `e' into a boolean expression: either through
+               ///   an implicit conversion, or through an `operator true' invocation
+               /// </summary>
+               public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
+               {
+                       e = e.Resolve (ec);
+                       if (e == null)
+                               return null;
+
+                       Expression converted = e;
+                       if (e.Type != TypeManager.bool_type)
+                               converted = Expression.ConvertImplicit (ec, e, TypeManager.bool_type, new Location (-1));
+
+                       //
+                       // If no implicit conversion to bool exists, try using `operator true'
+                       //
+                       if (converted == null){
+                               Expression operator_true = Expression.GetOperatorTrue (ec, e, loc);
+                               if (operator_true == null){
+                                       Report.Error (
+                                               31, loc, "Can not convert the expression to a boolean");
+                                       return null;
+                               }
+                               e = operator_true;
+                       } else
+                               e = converted;
+
+                       return e;
+               }
+               
                /// <summary>
                ///   Computes the MethodGroup for the user-defined conversion
                ///   operators from source_type to target_type.  `look_for_explicit'
@@ -1515,17 +1590,10 @@ namespace Mono.CSharp {
                        Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
                        string op_name;
 
-                       //
-                       // FIXME : How does the False operator come into the picture ?
-                       // This doesn't look complete and very correct !
-                       //
-                       if (target_type == TypeManager.bool_type && !look_for_explicit)
-                               op_name = "op_True";
-                       else
-                               op_name = "op_Implicit";
+                       op_name = "op_Implicit";
 
                        MethodGroupExpr union3;
-                       
+
                        mg1 = MethodLookup (ec, source_type, op_name, loc);
                        if (source_type.BaseType != null)
                                mg2 = MethodLookup (ec, source_type.BaseType, op_name, loc);
@@ -1593,7 +1661,6 @@ namespace Mono.CSharp {
                                return null;
                        
                        Type most_specific_source, most_specific_target;
-
 #if BLAH
                        foreach (MethodBase m in union.Methods){
                                Console.WriteLine ("Name: " + m.Name);
@@ -1708,14 +1775,14 @@ namespace Mono.CSharp {
                        e = ImplicitReferenceConversion (expr, target_type);
                        if (e != null)
                                return e;
-
+                       
                        if ((target_type == TypeManager.enum_type ||
                             target_type.IsSubclassOf (TypeManager.enum_type)) &&
                            expr is IntLiteral){
                                IntLiteral i = (IntLiteral) expr;
 
                                if (i.Value == 0)
-                                       return new EmptyCast (expr, target_type);
+                                       return new EnumConstant ((Constant) expr, target_type);
                        }
 
                        if (ec.InUnsafe) {
@@ -1754,9 +1821,6 @@ namespace Mono.CSharp {
                {
                        int value = ic.Value;
 
-                       //
-                       // FIXME: This could return constants instead of EmptyCasts
-                       //
                        if (target_type == TypeManager.sbyte_type){
                                if (value >= SByte.MinValue && value <= SByte.MaxValue)
                                        return new SByteConstant ((sbyte) value);
@@ -2408,7 +2472,7 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Reports that we were expecting `expr' to be of class `expected'
                /// </summary>
-               public void Error118 (string expected)
+               public void Error_UnexpectedKind (string expected)
                {
                        string kind = "Unknown";
                        
@@ -2418,7 +2482,7 @@ namespace Mono.CSharp {
                               "' where a `" + expected + "' was expected");
                }
 
-               public void Error118 (ResolveFlags flags)
+               public void Error_UnexpectedKind (ResolveFlags flags)
                {
                        ArrayList valid = new ArrayList (10);
 
@@ -2934,13 +2998,6 @@ namespace Mono.CSharp {
                        this.child = child;
                }
 
-               public Expression Peel ()
-               {
-                       if (child is EmptyCast)
-                               return ((EmptyCast) child).Peel ();
-                       return child;
-               }
-
                public override Expression DoResolve (EmitContext ec)
                {
                        // This should never be invoked, we are born in fully
@@ -3089,10 +3146,10 @@ namespace Mono.CSharp {
        public class BoxedCast : EmptyCast {
 
                public BoxedCast (Expression expr)
-                       : base (expr, TypeManager.object_type)
+                       : base (expr, TypeManager.object_type) 
                {
                }
-
+               
                public override Expression DoResolve (EmitContext ec)
                {
                        // This should never be invoked, we are born in fully
@@ -3175,6 +3232,11 @@ namespace Mono.CSharp {
                        return this;
                }
 
+               public override string ToString ()
+               {
+                       return String.Format ("ConvCast ({0}, {1})", mode, child);
+               }
+               
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
@@ -3442,7 +3504,7 @@ namespace Mono.CSharp {
        ///   The downside of this is that we might be hitting `LookupType' too many
        ///   times with this scheme.
        /// </remarks>
-       public class SimpleName : Expression, ITypeExpression {
+       public class SimpleName : Expression {
                public readonly string Name;
 
                //
@@ -3512,7 +3574,7 @@ namespace Mono.CSharp {
                        return SimpleNameResolve (ec, null, true);
                }
 
-               public Expression DoResolveType (EmitContext ec)
+               public override Expression ResolveAsTypeStep (EmitContext ec)
                {
                        DeclSpace ds = ec.DeclSpace;
                        Namespace ns = ds.Namespace;
@@ -3642,7 +3704,7 @@ namespace Mono.CSharp {
                                e = MemberLookup (ec, ec.ContainerType, Name, loc);
 
                        if (e == null)
-                               return DoResolveType (ec);
+                               return ResolveAsTypeStep (ec);
 
                        if (e is TypeExpr)
                                return e;
@@ -3662,7 +3724,8 @@ namespace Mono.CSharp {
                                        return e;
 
                                if (!me.IsStatic &&
-                                   TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) {
+                                   TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType) &&
+                                   !me.InstanceExpression.Type.IsSubclassOf (me.DeclaringType)) {
                                        Error (38, "Cannot access nonstatic member `" + me.Name + "' of " +
                                               "outer type `" + me.DeclaringType + "' via nested type `" +
                                               me.InstanceExpression.Type + "'");
@@ -3707,7 +3770,7 @@ namespace Mono.CSharp {
        /// <summary>
        ///   Fully resolved expression that evaluates to a type
        /// </summary>
-       public class TypeExpr : Expression, ITypeExpression {
+       public class TypeExpr : Expression {
                public TypeExpr (Type t, Location l)
                {
                        Type = t;
@@ -3715,7 +3778,7 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-               public virtual Expression DoResolveType (EmitContext ec)
+               public override Expression ResolveAsTypeStep (EmitContext ec)
                {
                        return this;
                }
@@ -3749,7 +3812,7 @@ namespace Mono.CSharp {
                        this.name = name;
                }
 
-               public override Expression DoResolveType (EmitContext ec)
+               public override Expression ResolveAsTypeStep (EmitContext ec)
                {
                        if (type == null)
                                type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
@@ -3758,7 +3821,7 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       return DoResolveType (ec);
+                       return ResolveAsTypeStep (ec);
                }
 
                public override void Emit (EmitContext ec)
@@ -4035,8 +4098,10 @@ namespace Mono.CSharp {
                        // InitOnly fields can only be assigned in constructors
                        //
 
-                       if (ec.IsConstructor)
-                               return this;
+                       if (ec.IsConstructor){
+                               if (ec.ContainerType == FieldInfo.DeclaringType)
+                                       return this;
+                       }
 
                        Report_AssignToReadonly (true);
                        
@@ -4066,7 +4131,7 @@ namespace Mono.CSharp {
                                if (instance_expr.Type.IsValueType){
                                        IMemoryLocation ml;
                                        LocalTemporary tempo = null;
-                                       
+
                                        if (!(instance_expr is IMemoryLocation)){
                                                tempo = new LocalTemporary (
                                                        ec, instance_expr.Type);
@@ -4173,11 +4238,18 @@ namespace Mono.CSharp {
                        if (FieldInfo.IsStatic)
                                ig.Emit (OpCodes.Ldsflda, FieldInfo);
                        else {
-#if false
-                               if (instance_expr is IMemoryLocation)
-                                       ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
-                               else
-#endif
+                               //
+                               // In the case of `This', we call the AddressOf method, which will
+                               // only load the pointer, and not perform an Ldobj immediately after
+                               // the value has been loaded into the stack.
+                               //
+                               if (instance_expr is This)
+                                       ((This)instance_expr).AddressOf (ec, AddressOp.LoadStore);
+                               else if (instance_expr.Type.IsValueType && instance_expr is IMemoryLocation){
+                                       IMemoryLocation ml = (IMemoryLocation) instance_expr;
+
+                                       ml.AddressOf (ec, AddressOp.LoadStore);
+                               } else
                                        instance_expr.Emit (ec);
                                ig.Emit (OpCodes.Ldflda, FieldInfo);
                        }