2009-01-23 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
index 1dbd7500487cf01dd88c1b7af44acd6726e9a08a..93e4db14fc4def3eaea94eb2b4a143ddf83868b1 100644 (file)
@@ -1270,7 +1270,7 @@ namespace Mono.CSharp {
                                t_is_nullable = true;
                        }
 
-                       if (t.IsValueType) {
+                       if (TypeManager.IsStruct (t)) {
                                if (d == t) {
                                        //
                                        // D and T are the same value types but D can be null
@@ -1298,7 +1298,7 @@ namespace Mono.CSharp {
                                if (TypeManager.IsGenericParameter (t))
                                        return ResolveGenericParameter (d, t);
 
-                               if (d.IsValueType) {
+                               if (TypeManager.IsStruct (d)) {
                                        bool temp;
                                        if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
                                                return CreateConstantResult (true);
@@ -1324,10 +1324,10 @@ namespace Mono.CSharp {
 #if GMCS_SOURCE
                        GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
                        if (constraints != null) {
-                               if (constraints.IsReferenceType && d.IsValueType)
+                               if (constraints.IsReferenceType && TypeManager.IsStruct (d))
                                        return CreateConstantResult (false);
 
-                               if (constraints.IsValueType && !d.IsValueType)
+                               if (constraints.IsValueType && !TypeManager.IsStruct (d))
                                        return CreateConstantResult (TypeManager.IsEqual (d, t));
                        }
 
@@ -1445,6 +1445,12 @@ namespace Mono.CSharp {
                protected override string OperatorName {
                        get { return "as"; }
                }
+
+               public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+               {
+                       type = storey.MutateType (type);
+                       base.MutateHoistedGenericType (storey);
+               }
        
                public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
                {
@@ -2532,13 +2538,9 @@ namespace Mono.CSharp {
 
                        // The conversion rules are ignored in enum context but why
                        if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
-                               left = lc = EnumLiftUp (ec, lc, rc, loc);
-                               if (lc == null)
-                                       return null;
-
-                               right = rc = EnumLiftUp (ec, rc, lc, loc);
-                               if (rc == null)
-                                       return null;
+                               lc = EnumLiftUp (ec, lc, rc, loc);
+                               if (lc != null)
+                                       rc = EnumLiftUp (ec, rc, lc, loc);
                        }
 
                        if (rc != null && lc != null) {
@@ -2578,9 +2580,9 @@ namespace Mono.CSharp {
 
                        if (RootContext.Version >= LanguageVersion.ISO_2 &&
                                ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
-                               (left.Type.IsValueType && right is NullLiteral) ||
+                               (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
                                (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
-                               (right.Type.IsValueType && left is NullLiteral)))
+                               (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
                                return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
 
                        return DoResolveCore (ec, left, right);
@@ -2892,7 +2894,7 @@ namespace Mono.CSharp {
                                        return null;
                        } else if (l.IsInterface) {
                                l = TypeManager.object_type;
-                       } else if (l.IsValueType) {
+                       } else if (TypeManager.IsStruct (l)) {
                                return null;
                        }
 
@@ -2902,7 +2904,7 @@ namespace Mono.CSharp {
                                        return null;
                        } else if (r.IsInterface) {
                                r = TypeManager.object_type;
-                       } else if (r.IsValueType) {
+                       } else if (TypeManager.IsStruct (r)) {
                                return null;
                        }
 
@@ -4030,7 +4032,7 @@ namespace Mono.CSharp {
                LocalTemporary temp;
 
                #region Abstract
-               public abstract HoistedVariable HoistedVariable { get; }
+               public abstract HoistedVariable GetHoistedVariable (EmitContext ec);
                public abstract bool IsFixed { get; }
                public abstract bool IsRef { get; }
                public abstract string Name { get; }
@@ -4049,8 +4051,9 @@ namespace Mono.CSharp {
 
                public void AddressOf (EmitContext ec, AddressOp mode)
                {
-                       if (IsHoistedEmitRequired (ec)) {
-                               HoistedVariable.AddressOf (ec, mode);
+                       HoistedVariable hv = GetHoistedVariable (ec);
+                       if (hv != null) {
+                               hv.AddressOf (ec, mode);
                                return;
                        }
 
@@ -4082,8 +4085,9 @@ namespace Mono.CSharp {
                {
                        Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
 
-                       if (IsHoistedEmitRequired (ec)) {
-                               HoistedVariable.Emit (ec, leave_copy);
+                       HoistedVariable hv = GetHoistedVariable (ec);
+                       if (hv != null) {
+                               hv.Emit (ec, leave_copy);
                                return;
                        }
 
@@ -4110,8 +4114,9 @@ namespace Mono.CSharp {
                public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
                                        bool prepare_for_load)
                {
-                       if (IsHoistedEmitRequired (ec)) {
-                               HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
+                       HoistedVariable hv = GetHoistedVariable (ec);
+                       if (hv != null) {
+                               hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
                                return;
                        }
 
@@ -4149,15 +4154,7 @@ namespace Mono.CSharp {
                }
 
                public bool IsHoisted {
-                       get { return HoistedVariable != null; }
-               }
-
-               protected virtual bool IsHoistedEmitRequired (EmitContext ec)
-               {
-                       //
-                       // Default implementation return true when there is a hosted variable
-                       //
-                       return HoistedVariable != null;
+                       get { return GetHoistedVariable (null) != null; }
                }
 
                public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
@@ -4199,8 +4196,9 @@ namespace Mono.CSharp {
                        get { return local_info.VariableInfo; }
                }
 
-               public override HoistedVariable HoistedVariable {
-                       get { return local_info.HoistedVariableReference; }
+               public override HoistedVariable GetHoistedVariable (EmitContext ec)
+               {
+                       return local_info.HoistedVariableReference;
                }
 
                //              
@@ -4369,12 +4367,10 @@ namespace Mono.CSharp {
        /// </summary>
        public class ParameterReference : VariableReference {
                readonly ToplevelParameterInfo pi;
-               readonly ToplevelBlock referenced;
 
-               public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
+               public ParameterReference (ToplevelParameterInfo pi, Location loc)
                {
                        this.pi = pi;
-                       this.referenced = referenced;
                        this.loc = loc;
                }
 
@@ -4386,8 +4382,9 @@ namespace Mono.CSharp {
                        get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
                }
 
-               public override HoistedVariable HoistedVariable {
-                       get { return pi.Parameter.HoistedVariableReference; }
+               public override HoistedVariable GetHoistedVariable (EmitContext ec)
+               {
+                       return pi.Parameter.HoistedVariableReference;
                }
 
                //
@@ -4447,24 +4444,38 @@ namespace Mono.CSharp {
                        if (am == null)
                                return true;
 
-                       ToplevelBlock declared = pi.Block;
-                       if (declared != referenced) {
-                               if (IsRef) {
-                                       Report.Error (1628, loc,
-                                               "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
-                                               Name, am.ContainerType);
-                                       return false;
+                       Block b = ec.CurrentBlock;
+                       while (b != null) {
+                               IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
+                               for (int i = 0; i < p.Length; ++i) {
+                                       if (p [i] != Parameter)
+                                               continue;
+
+                                       //
+                                       // Skip closest anonymous method parameters
+                                       //
+                                       if (b == ec.CurrentBlock && !am.IsIterator)
+                                               return true;
+
+                                       if (IsRef) {
+                                               Report.Error (1628, loc,
+                                                       "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
+                                                       Name, am.ContainerType);
+                                       }
+
+                                       b = null;
+                                       break;
                                }
-                       } else {
-                               if (!am.IsIterator)
-                                       return true;
+
+                               if (b != null)
+                                       b = b.Toplevel.Parent;
                        }
 
-                       if (ec.IsVariableCapturingRequired) {
-                               if (pi.Parameter.HasAddressTaken)
-                                       AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
+                       if (pi.Parameter.HasAddressTaken)
+                               AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
 
-                               AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
+                       if (ec.IsVariableCapturingRequired) {
+                               AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
                                storey.CaptureParameter (ec, this);
                        }
 
@@ -4482,7 +4493,7 @@ namespace Mono.CSharp {
                        if (pr == null)
                                return false;
 
-                       return Name == pr.Name && referenced == pr.referenced;
+                       return Name == pr.Name;
                }
                
                protected override void CloneTo (CloneContext clonectx, Expression target)
@@ -4492,8 +4503,9 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (EmitContext ec)
                {
-                       if (IsHoistedEmitRequired (ec))
-                               return HoistedVariable.CreateExpressionTree (ec);
+                       HoistedVariable hv = GetHoistedVariable (ec);
+                       if (hv != null)
+                               return hv.CreateExpressionTree (ec);
 
                        return Parameter.ExpressionTreeVariableReference ();
                }
@@ -4837,7 +4849,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
+                       if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
                                if (mg.IsBase)
                                        Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
                                else
@@ -4996,7 +5008,7 @@ namespace Mono.CSharp {
                        bool is_static = method.IsStatic;
                        if (!is_static){
                                this_call = instance_expr is This;
-                               if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
+                               if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type) || (!this_call && TypeManager.IsStruct (instance_expr.Type)))
                                        struct_call = true;
 
                                //
@@ -5009,12 +5021,12 @@ namespace Mono.CSharp {
                                        //
                                        // Push the instance expression
                                        //
-                                       if (TypeManager.IsValueType (iexpr_type)) {
+                                       if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
                                                //
                                                // Special case: calls to a function declared in a 
                                                // reference-type with a value-type argument need
                                                // to have their value boxed.
-                                               if (decl_type.IsValueType ||
+                                               if (TypeManager.IsStruct (decl_type) ||
                                                    TypeManager.IsGenericParameter (iexpr_type)) {
                                                        //
                                                        // If the expression implements IMemoryLocation, then
@@ -5059,16 +5071,17 @@ namespace Mono.CSharp {
                        if (!omit_args)
                                EmitArguments (ec, Arguments, dup_args, this_arg);
 
-#if GMCS_SOURCE
-                       if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
-                               ig.Emit (OpCodes.Constrained, instance_expr.Type);
-#endif
-
                        OpCode call_op;
-                       if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
+                       if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
                                call_op = OpCodes.Call;
-                       else
+                       } else {
                                call_op = OpCodes.Callvirt;
+                               
+#if GMCS_SOURCE
+                               if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
+                                       ig.Emit (OpCodes.Constrained, instance_expr.Type);
+#endif
+                       }
 
                        if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
                                Type[] varargs_types = GetVarargsTypes (method, Arguments);
@@ -5431,7 +5444,7 @@ namespace Mono.CSharp {
                                return null;
                        }
 
-                       bool is_struct = type.IsValueType;
+                       bool is_struct = TypeManager.IsStruct (type);
                        eclass = ExprClass.Value;
 
                        //
@@ -5620,7 +5633,7 @@ namespace Mono.CSharp {
                                return;
                        }
 
-                       if (!type.IsValueType){
+                       if (!TypeManager.IsStruct (type)){
                                //
                                // We throw an exception.  So far, I believe we only need to support
                                // value types:
@@ -6267,7 +6280,7 @@ namespace Mono.CSharp {
                                        // If we are dealing with a struct, get the
                                        // address of it, so we can store it.
                                        //
-                                       if ((dims == 1) && etype.IsValueType &&
+                                       if ((dims == 1) && TypeManager.IsStruct (etype) &&
                                            (!TypeManager.IsBuiltinOrEnum (etype) ||
                                             etype == TypeManager.decimal_type)) {
 
@@ -6517,8 +6530,9 @@ namespace Mono.CSharp {
                        return this;
                }
 
-               public override HoistedVariable HoistedVariable {
-                       get { return null; }
+               public override HoistedVariable GetHoistedVariable (EmitContext ec)
+               {
+                       return null;
                }
        }
        
@@ -6571,17 +6585,25 @@ namespace Mono.CSharp {
                        get { return false; }
                }
 
-               protected override bool IsHoistedEmitRequired (EmitContext ec)
+               public override HoistedVariable GetHoistedVariable (EmitContext ec)
                {
-                       //
-                       // Handle 'this' differently, it cannot be assigned hence
-                       // when we are not inside anonymous method we can emit direct access 
-                       //
-                       return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
-               }
+                       // Is null when probing IsHoisted
+                       if (ec == null)
+                               return null;
+
+                       if (ec.CurrentAnonymousMethod == null)
+                               return null;
+
+                       AnonymousMethodStorey storey = ec.CurrentAnonymousMethod.Storey;
+                       while (storey != null) {
+                               AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
+                               if (temp == null)
+                                       return storey.HoistedThis;
 
-               public override HoistedVariable HoistedVariable {
-                       get { return TopToplevelBlock.HoistedThisVariable; }
+                               storey = temp;
+                       }
+
+                       return null;
                }
 
                public override bool IsRef {
@@ -6592,15 +6614,6 @@ namespace Mono.CSharp {
                        get { return ThisVariable.Instance; }
                }
 
-               // TODO: Move to ToplevelBlock
-               ToplevelBlock TopToplevelBlock {
-                       get {
-                               ToplevelBlock tl = block.Toplevel;
-                               while (tl.Parent != null) tl = tl.Parent.Toplevel;
-                               return tl;
-                       }
-               }
-
                public static bool IsThisAvailable (EmitContext ec)
                {
                        if (ec.IsStatic || ec.IsInFieldInitializer)
@@ -6644,24 +6657,8 @@ namespace Mono.CSharp {
                                        variable_info = block.Toplevel.ThisVariable.VariableInfo;
 
                                AnonymousExpression am = ec.CurrentAnonymousMethod;
-                               if (am != null) {
-                                       //
-                                       // this is hoisted to very top level block
-                                       //
-                                       if (ec.IsVariableCapturingRequired) {
-                                               //
-                                               // TODO: it should be optimized, see test-anon-75.cs
-                                               //
-                                               // `this' variable has its own scope which is mostly empty
-                                               // and causes creation of extraneous storey references.
-                                               // Also it's hard to remove `this' dependencies when we Undo
-                                               // this access.
-                                               //
-                                               AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
-                                               if (HoistedVariable == null) {
-                                                       TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
-                                               }
-                                       }
+                               if (am != null && ec.IsVariableCapturingRequired) {
+                                       am.SetHasThisAccess ();
                                }
                        }
                        
@@ -6673,7 +6670,7 @@ namespace Mono.CSharp {
                //
                public override void CheckMarshalByRefAccess (EmitContext ec)
                {
-                       if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
+                       if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
                            !variable_info.IsAssigned (ec)) {
                                Error (188, "The `this' object cannot be used before all of its " +
                                       "fields are assigned to");
@@ -6750,11 +6747,6 @@ namespace Mono.CSharp {
                        target.block = clonectx.LookupBlock (block);
                }
 
-               public void RemoveHoisting ()
-               {
-                       TopToplevelBlock.HoistedThisVariable = null;
-               }
-
                public override void SetHasAddressTaken ()
                {
                        // Nothing
@@ -7821,7 +7813,7 @@ namespace Mono.CSharp {
                        if (type.IsPointer)
                                return MakePointerAccess (ec, type);
 
-                       if (Expr.eclass != ExprClass.Variable && type.IsValueType)
+                       if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
                                Error_CannotModifyIntermediateExpressionValue (ec);
 
                        return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
@@ -7952,7 +7944,7 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Ldelem_I);
                        else if (TypeManager.IsEnumType (type)){
                                EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
-                       } else if (type.IsValueType){
+                       } else if (TypeManager.IsStruct (type)){
                                ig.Emit (OpCodes.Ldelema, type);
                                ig.Emit (OpCodes.Ldobj, type);
 #if GMCS_SOURCE
@@ -7999,7 +7991,7 @@ namespace Mono.CSharp {
                                 has_type_arg = true;
                                is_stobj = true;
                                 return OpCodes.Stobj;
-                       } else if (t.IsValueType) {
+                       } else if (TypeManager.IsStruct (t)) {
                                has_type_arg = true;
                                is_stobj = true;
                                return OpCodes.Stobj;