2007-12-06 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / mcs / expression.cs
index 0cc565be7a277e407b258ccdf548814942a77080..7c9d1d1d7cbd95d4db5da190c744b021e1a9d2d2 100644 (file)
@@ -1077,13 +1077,23 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return null;
                        
-                       if (expr.Type.IsPointer) {
-                               Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
+                       if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
+                               Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
+                                       OperatorName);
                                return null;
                        }
+
+                       if (expr.Type == TypeManager.anonymous_method_type) {
+                               Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
+                                       OperatorName);
+                               return null;
+                       }
+
                        return this;
                }
 
+               protected abstract string OperatorName { get; }
+
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        Probe target = (Probe) t;
@@ -1102,131 +1112,135 @@ namespace Mono.CSharp {
                        : base (expr, probe_type, l)
                {
                }
-
-               enum Action {
-                       AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
-               }
-
-               Action action;
                
                public override void Emit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
                        expr.Emit (ec);
-
-                       switch (action){
-                       case Action.AlwaysFalse:
-                               ig.Emit (OpCodes.Pop);
-                               IntConstant.EmitInt (ig, 0);
-                               return;
-                       case Action.AlwaysTrue:
-                               ig.Emit (OpCodes.Pop);
-                               IntConstant.EmitInt (ig, 1);
-                               return;
-                       case Action.LeaveOnStack:
-                               // the `e != null' rule.
-                               ig.Emit (OpCodes.Ldnull);
-                               ig.Emit (OpCodes.Ceq);
-                               ig.Emit (OpCodes.Ldc_I4_0);
-                               ig.Emit (OpCodes.Ceq);
-                               return;
-                       case Action.Probe:
-                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
-                               ig.Emit (OpCodes.Ldnull);
-                               ig.Emit (OpCodes.Cgt_Un);
-                               return;
-                       }
-                       throw new Exception ("never reached");
+                       ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                       ig.Emit (OpCodes.Ldnull);
+                       ig.Emit (OpCodes.Cgt_Un);
                }
 
                public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
                {
                        ILGenerator ig = ec.ig;
 
-                       switch (action){
-                       case Action.AlwaysFalse:
-                               if (! on_true)
-                                       ig.Emit (OpCodes.Br, target);
-                               
-                               return;
-                       case Action.AlwaysTrue:
-                               if (on_true)
-                                       ig.Emit (OpCodes.Br, target);
-                               
-                               return;
-                       case Action.LeaveOnStack:
-                               // the `e != null' rule.
-                               expr.Emit (ec);
-                               ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
-                               return;
-                       case Action.Probe:
-                               expr.Emit (ec);
-                               ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
-                               ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
-                               return;
-                       }
-                       throw new Exception ("never reached");
+                       expr.Emit (ec);
+                       ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+                       ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
                }
 
-               public override Expression DoResolve (EmitContext ec)
+               Expression CreateConstantResult (bool result)
                {
-                       Expression e = base.DoResolve (ec);
+                       if (result)
+                               Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
+                                       TypeManager.CSharpName (probe_type_expr.Type));
+                       else
+                               Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
+                                       TypeManager.CSharpName (probe_type_expr.Type));
+
+                       return new BoolConstant (result, loc);
+               }
 
-                       if ((e == null) || (expr == null))
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (base.DoResolve (ec) == null)
                                return null;
 
-                       Type etype = expr.Type;
+                       Type d = expr.Type;
+                       bool d_is_nullable = false;
+
+                       if (expr is Constant) {
+                               //
+                               // If E is a method group or the null literal, of if the type of E is a reference
+                               // type or a nullable type and the value of E is null, the result is false
+                               //
+                               if (((Constant) expr).GetValue () == null)
+                                       return CreateConstantResult (false);
+                       } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
+                               d = TypeManager.GetTypeArguments (d) [0];
+                               d_is_nullable = true;
+                       }
+
                        type = TypeManager.bool_type;
                        eclass = ExprClass.Value;
+                       Type t = probe_type_expr.Type;
+                       bool t_is_nullable = false;
+                       if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
+                               t = TypeManager.GetTypeArguments (t) [0];
+                               t_is_nullable = true;
+                       }
 
-                       //
-                       // First case, if at compile time, there is an implicit conversion
-                       // then e != null (objects) or true (value types)
-                       //
-                       Type probe_type = probe_type_expr.Type;
-                       e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
-                       if (e != null){
-                               expr = e;
-                               if (etype.IsValueType)
-                                       action = Action.AlwaysTrue;
-                               else
-                                       action = Action.LeaveOnStack;
-
-                               Constant c = e as Constant;
-                               if (c != null && c.Type != etype) {
-                                       action = Action.AlwaysFalse;
-                                       Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
-                                               TypeManager.CSharpName (probe_type));
-                               } else if (etype.IsValueType) {
-                                       Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
-                                               TypeManager.CSharpName (probe_type));
+                       if (t.IsValueType) {
+                               if (d == t) {
+                                       //
+                                       // D and T are the same value types but D can be null
+                                       //
+                                       if (d_is_nullable && !t_is_nullable)
+                                               return Nullable.HasValue.Create (expr, ec);
+                                       
+                                       //
+                                       // The result is true if D and T are the same value types
+                                       //
+                                       return CreateConstantResult (true);
                                }
-                               return this;
-                       }
-                       
-                       if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
-                               if (TypeManager.IsGenericParameter (etype))
-                                       expr = new BoxedCast (expr, etype);
+
+                               if (TypeManager.IsGenericParameter (d))
+                                       return ResolveGenericParameter (t, d);
 
                                //
-                               // Second case: explicit reference convresion
+                               // An unboxing conversion exists
                                //
-                               if (expr is NullLiteral)
-                                       action = Action.AlwaysFalse;
-                               else
-                                       action = Action.Probe;
-                       } else if (TypeManager.ContainsGenericParameters (etype) ||
-                                  TypeManager.ContainsGenericParameters (probe_type)) {
-                               expr = new BoxedCast (expr, etype);
-                               action = Action.Probe;
+                               if (Convert.ExplicitReferenceConversionExists (d, t))
+                                       return this;
                        } else {
-                               action = Action.AlwaysFalse;
-                               if (!(probe_type.IsInterface || expr.Type.IsInterface))
-                                       Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
+                               if (TypeManager.IsGenericParameter (t))
+                                       return ResolveGenericParameter (d, t);
+
+                               if (d.IsValueType) {
+                                       bool temp;
+                                       if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
+                                               return CreateConstantResult (true);
+                               } else {
+                                       if (TypeManager.IsGenericParameter (d))
+                                               return ResolveGenericParameter (t, d);
+
+                                       if (TypeManager.ContainsGenericParameters (d))
+                                               return this;
+
+                                       if (Convert.ImplicitReferenceConversionExists (expr, t) ||
+                                               Convert.ExplicitReferenceConversionExists (d, t)) {
+                                               return this;
+                                       }
+                               }
                        }
 
+                       return CreateConstantResult (false);
+               }
+
+               Expression ResolveGenericParameter (Type d, Type t)
+               {
+#if GMCS_SOURCE
+                       GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
+                       if (constraints != null) {
+                               if (constraints.IsReferenceType && d.IsValueType)
+                                       return CreateConstantResult (false);
+
+                               if (constraints.IsValueType && !d.IsValueType)
+                                       return CreateConstantResult (false);
+                       }
+
+                       expr = new BoxedCast (expr, d);
                        return this;
+#else
+                       return null;
+#endif
+               }
+               
+               protected override string OperatorName {
+                       get { return "is"; }
                }
        }
 
@@ -1335,6 +1349,10 @@ namespace Mono.CSharp {
                        Error_CannotConvertType (etype, type, loc);
                        return null;
                }
+
+               protected override string OperatorName {
+                       get { return "as"; }
+               }
        
                public override bool GetAttributableValue (Type value_type, out object value)
                {
@@ -1422,6 +1440,68 @@ namespace Mono.CSharp {
                        target.expr = expr.Clone (clonectx);
                }
        }
+       
+       //
+       // C# 2.0 Default value expression
+       //
+       public class DefaultValueExpression : Expression
+       {
+               Expression expr;
+
+               public DefaultValueExpression (Expression expr, Location loc)
+               {
+                       this.expr = expr;
+                       this.loc = loc;
+               }
+
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
+                       if (texpr == null)
+                               return null;
+
+                       type = texpr.Type;
+
+                       if (type == TypeManager.void_type) {
+                               Error_VoidInvalidInTheContext (loc);
+                               return null;
+                       }
+
+                       if (TypeManager.IsGenericParameter (type))
+                       {
+                               GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
+                               if (constraints != null && constraints.IsReferenceType)
+                                       return new NullDefault (new NullLiteral (Location), type);
+                       }
+                       else
+                       {
+                               Constant c = New.Constantify(type);
+                               if (c != null)
+                                       return new NullDefault (c, type);
+
+                               if (!TypeManager.IsValueType (type))
+                                       return new NullDefault (new NullLiteral (Location), type);
+                       }
+                       eclass = ExprClass.Variable;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       LocalTemporary temp_storage = new LocalTemporary(type);
+
+                       temp_storage.AddressOf(ec, AddressOp.LoadStore);
+                       ec.ig.Emit(OpCodes.Initobj, type);
+                       temp_storage.Emit(ec);
+               }
+               
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       DefaultValueExpression target = (DefaultValueExpression) t;
+                       
+                       target.expr = expr.Clone (clonectx);
+               }
+       }
 
        /// <summary>
        ///   Binary operators
@@ -1619,6 +1699,14 @@ namespace Mono.CSharp {
                {
                        if (!IsApplicable_String (ec, left, right, oper))
                                return false;
+                       
+                       Type l = left.Type;
+                       Type r = right.Type;
+                       if (OverloadResolve_PredefinedIntegral (ec) ||
+                               OverloadResolve_PredefinedFloating (ec)) {
+                               Error_OperatorAmbiguous (loc, oper, l, r);
+                       }
+                       
                        Type t = TypeManager.string_type;
                        if (Convert.ImplicitConversionExists (ec, left, t))
                                left = ForceConversion (ec, left, t);
@@ -1889,41 +1977,43 @@ namespace Mono.CSharp {
                        }
 
                        //
-                       // Step 0: String concatenation (because overloading will get this wrong)
+                       // String concatenation
+                       // 
+                       // string operator + (string x, string y);
+                       // string operator + (string x, object y);
+                       // string operator + (object x, string y);
                        //
-                       if (oper == Operator.Addition){
-                               //
-                               // If any of the arguments is a string, cast to string
+                       if (oper == Operator.Addition && !TypeManager.IsDelegateType (l)) {
+                               // 
+                               // Either left or right expression is implicitly convertible to string
                                //
-                               
-                               // Simple constant folding
-                               if (left is StringConstant && right is StringConstant)
-                                       return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
-                               
-                               if (l == TypeManager.string_type || r == TypeManager.string_type) {
-
+                               if (OverloadResolve_PredefinedString (ec, oper)) {
                                        if (r == TypeManager.void_type || l == TypeManager.void_type) {
                                                Error_OperatorCannotBeApplied ();
                                                return null;
                                        }
 
-                                       // try to fold it in on the left
-                                       if (left is StringConcat) {
+                                       //
+                                       // Constants folding for strings and nulls
+                                       //
+                                       if (left.Type == TypeManager.string_type && right.Type == TypeManager.string_type &&
+                                               left is Constant && right is Constant) {
+                                               string lvalue = (string)((Constant) left).GetValue ();
+                                               string rvalue = (string)((Constant) right).GetValue ();
+                                               return new StringConstant (lvalue + rvalue, left.Location);
+                                       }
 
-                                               //
-                                               // We have to test here for not-null, since we can be doubly-resolved
-                                               // take care of not appending twice
-                                               //
-                                               if (type == null){
-                                                       type = TypeManager.string_type;
-                                                       ((StringConcat) left).Append (ec, right);
-                                                       return left.Resolve (ec);
-                                               } else {
-                                                       return left;
-                                               }
+                                       // 
+                                       // Append to existing string concatenation
+                                       //
+                                       if (left is StringConcat) {
+                                               ((StringConcat) left).Append (ec, right);
+                                               return left;
                                        }
 
-                                       // Otherwise, start a new concat expression
+                                       //
+                                       // Otherwise, start a new concat expression using converted expression
+                                       //
                                        return new StringConcat (ec, loc, left, right).Resolve (ec);
                                }
 
@@ -3834,6 +3924,10 @@ namespace Mono.CSharp {
 
                public bool IsAssigned (EmitContext ec, Location loc)
                {
+                       // HACK: Variables are not captured in probing mode
+                       if (ec.IsInProbingMode)
+                               return true;
+                       
                        if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
                                return true;
 
@@ -4182,21 +4276,18 @@ namespace Mono.CSharp {
                        MethodInfo method = (MethodInfo)mg;
                        if (method != null) {
                                type = TypeManager.TypeToCoreType (method.ReturnType);
+
+                               // TODO: this is a copy of mg.ResolveMemberAccess method
                                Expression iexpr = mg.InstanceExpression;
                                if (method.IsStatic) {
-                                       if (iexpr == null || 
-                                           iexpr is This || iexpr is EmptyExpression ||
-                                           mg.IdenticalTypeName) {
+                                       if (iexpr == null ||
+                                               iexpr is This || iexpr is EmptyExpression ||
+                                               mg.IdenticalTypeName) {
                                                mg.InstanceExpression = null;
                                        } else {
                                                MemberExpr.error176 (loc, mg.GetSignatureForError ());
                                                return null;
                                        }
-                               } else {
-                                       if (iexpr == null || iexpr is EmptyExpression) {
-                                               SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
-                                               return null;
-                                       }
                                }
                        }
 
@@ -6015,7 +6106,6 @@ namespace Mono.CSharp {
                                                      "Consider copying `this' to a local variable " +
                                                      "outside the anonymous method and using the " +
                                                      "local instead.");
-                                       return false;
                                }
 
                                RootScopeInfo host = block.Toplevel.RootScope;
@@ -6597,6 +6687,9 @@ namespace Mono.CSharp {
                                        "System.NullReferenceException");
                        }
 
+                       if (args != null)
+                               args.Resolve (ec);
+
                        Expression member_lookup;
                        member_lookup = MemberLookup (
                                ec.ContainerType, expr_type, expr_type, Identifier, loc);
@@ -6611,8 +6704,10 @@ namespace Mono.CSharp {
                                if (ex_method_lookup != null) {
                                        ex_method_lookup.ExtensionExpression = expr_resolved;
 
-                                       if (args != null)
+                                       if (args != null) {
+                                               ex_method_lookup.SetTypeArguments (args);
                                                return ex_method_lookup.ResolveGeneric (ec, args);
+                                       }
 
                                        return ex_method_lookup.DoResolve (ec);
                                }
@@ -6659,21 +6754,17 @@ namespace Mono.CSharp {
                        }
 
                        MemberExpr me = (MemberExpr) member_lookup;
-                       member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
-                       if (member_lookup == null)
-                               return me;
+                       me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
+                       if (me == null)
+                               return null;
 
                        if (args != null) {
-                               MethodGroupExpr mg = member_lookup as MethodGroupExpr;
-                               if (mg == null)
-                                       throw new InternalErrorException ();
-
-                               return mg.ResolveGeneric (ec, args);
+                               me.SetTypeArguments (args);
+                               return me.ResolveGeneric (ec, args);
                        }
 
                        if (original != null && !TypeManager.IsValueType (expr_type)) {
-                               me = member_lookup as MemberExpr;
-                               if (me != null && me.IsInstance) {
+                               if (me.IsInstance) {
                                        LocalVariableReference var = expr_resolved as LocalVariableReference;
                                        if (var != null && !var.VerifyAssigned (ec))
                                                return null;
@@ -6684,9 +6775,9 @@ namespace Mono.CSharp {
                        // check.
 
                        if (right_side != null)
-                               return member_lookup.DoResolveLValue (ec, right_side);
+                               return me.DoResolveLValue (ec, right_side);
                        else
-                               return member_lookup.DoResolve (ec);
+                               return me.DoResolve (ec);
                }
 
                public override Expression DoResolve (EmitContext ec)
@@ -7015,15 +7106,15 @@ namespace Mono.CSharp {
                        if (!CommonResolve (ec))
                                return null;
 
-                       Type t = Expr.Type;
-                       if (t.IsArray)
+                       type = Expr.Type;
+                       if (type.IsArray)
                                return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
 
-                       if (t.IsPointer)
-                               return MakePointerAccess (ec, t);
+                       if (type.IsPointer)
+                               return MakePointerAccess (ec, type);
 
-                       if (t.IsValueType)
-                               Error_CannotModiftyIntermediateExpressionValue ();
+                       if (Expr.eclass != ExprClass.Variable && type.IsValueType)
+                               Error_CannotModifyIntermediateExpressionValue (ec);
 
                        return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
                }
@@ -7634,7 +7725,7 @@ namespace Mono.CSharp {
 
                        // if the indexer returns a value type, and we try to set a field in it
                        if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
-                               Error_CannotModiftyIntermediateExpressionValue ();
+                               Error_CannotModifyIntermediateExpressionValue (ec);
                        }
 
                        Expression e = ResolveAccessor (ec, AccessorType.Set);
@@ -7887,31 +7978,18 @@ namespace Mono.CSharp {
                                left = ec.GetThis (loc);
 
                        MemberExpr me = (MemberExpr) member_lookup;
-                       
-                       Expression e = me.ResolveMemberAccess (ec, left, loc, null);
-
-                       if (e is PropertyExpr) {
-                               PropertyExpr pe = (PropertyExpr) e;
-                               pe.IsBase = true;
-                       } else if (e is EventExpr) {
-                               EventExpr ee = (EventExpr) e;
-                               ee.IsBase = true;
-                       }
-
-                       MethodGroupExpr mg = e as MethodGroupExpr;
-                       if (mg != null)
-                               mg.IsBase = true;
+                       me = me.ResolveMemberAccess (ec, left, loc, null);
+                       if (me == null)
+                               return null;
 
+                       me.IsBase = true;
                        if (args != null) {
-                               if (mg != null)
-                                       return mg.ResolveGeneric (ec, args);
-
-                               Report.Error (307, loc, "`{0}' cannot be used with type arguments",
-                                             Identifier);
-                               return null;
+                               args.Resolve (ec);
+                               me.SetTypeArguments (args);
+                               return me.ResolveGeneric (ec, args);
                        }
 
-                       return e;
+                       return me;
                }
 
                public override void Emit (EmitContext ec)
@@ -7923,7 +8001,8 @@ namespace Mono.CSharp {
                {
                        BaseAccess target = (BaseAccess) t;
 
-                       target.args = args.Clone ();
+                       if (args != null)
+                               target.args = args.Clone ();
                }
        }
 
@@ -8114,18 +8193,16 @@ namespace Mono.CSharp {
                        loc = l;
                }
 
-#if GMCS_SOURCE
                public Expression RemoveNullable ()
                {
                        if (dim.EndsWith ("?")) {
                                dim = dim.Substring (0, dim.Length - 1);
-                               if (dim == "")
+                               if (dim.Length == 0)
                                        return left;
                        }
 
                        return this;
                }
-#endif
 
                protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
                {