+
+ // <summary>
+ // Returns a stringified representation of the Operator
+ // </summary>
+ string OperName ()
+ {
+ switch (oper){
+ case Operator.Multiply:
+ return "*";
+ case Operator.Division:
+ return "/";
+ case Operator.Modulus:
+ return "%";
+ case Operator.Addition:
+ return "+";
+ case Operator.Subtraction:
+ return "-";
+ case Operator.LeftShift:
+ return "<<";
+ case Operator.RightShift:
+ return ">>";
+ case Operator.LessThan:
+ return "<";
+ case Operator.GreaterThan:
+ return ">";
+ case Operator.LessThanOrEqual:
+ return "<=";
+ case Operator.GreaterThanOrEqual:
+ return ">=";
+ case Operator.Equality:
+ return "==";
+ case Operator.Inequality:
+ return "!=";
+ case Operator.BitwiseAnd:
+ return "&";
+ case Operator.BitwiseOr:
+ return "|";
+ case Operator.ExclusiveOr:
+ return "^";
+ case Operator.LogicalOr:
+ return "||";
+ case Operator.LogicalAnd:
+ return "&&";
+ }
+
+ return oper.ToString ();
+ }
+
+ Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
+ {
+ if (expr.Type == target_type)
+ return expr;
+
+ return ConvertImplicit (ec, expr, target_type, new Location (-1));
+ }
+
+ //
+ // Note that handling the case l == Decimal || r == Decimal
+ // is taken care of by the Step 1 Operator Overload resolution.
+ //
+ bool DoNumericPromotions (EmitContext ec, Type l, Type r)
+ {
+ if (l == TypeManager.double_type || r == TypeManager.double_type){
+ //
+ // If either operand is of type double, the other operand is
+ // conveted to type double.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
+
+ type = TypeManager.double_type;
+ } else if (l == TypeManager.float_type || r == TypeManager.float_type){
+ //
+ // if either operand is of type float, th eother operand is
+ // converd to type float.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
+ type = TypeManager.float_type;
+ } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
+ Expression e;
+ Type other;
+ //
+ // If either operand is of type ulong, the other operand is
+ // converted to type ulong. or an error ocurrs if the other
+ // operand is of type sbyte, short, int or long
+ //
+
+ if (l == TypeManager.uint64_type){
+ if (r != TypeManager.uint64_type && right is IntLiteral){
+ e = TryImplicitIntConversion (l, (IntLiteral) right);
+ if (e != null)
+ right = e;
+ }
+ other = right.Type;
+ } else {
+ if (left is IntLiteral){
+ e = TryImplicitIntConversion (r, (IntLiteral) left);
+ if (e != null)
+ left = e;
+ }
+ other = left.Type;
+ }
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type) ||
+ (other == TypeManager.int64_type)){
+ string oper = OperName ();
+
+ Error (34, loc, "Operator `" + OperName ()
+ + "' is ambiguous on operands of type `"
+ + TypeManager.CSharpName (l) + "' "
+ + "and `" + TypeManager.CSharpName (r)
+ + "'");
+ }
+ type = TypeManager.uint64_type;
+ } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
+ //
+ // If either operand is of type long, the other operand is converted
+ // to type long.
+ //
+ if (l != TypeManager.int64_type)
+ left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
+ if (r != TypeManager.int64_type)
+ right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
+
+ type = TypeManager.int64_type;
+ } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
+ //
+ // If either operand is of type uint, and the other
+ // operand is of type sbyte, short or int, othe operands are
+ // converted to type long.
+ //
+ Type other = null;
+
+ if (l == TypeManager.uint32_type)
+ other = r;
+ else if (r == TypeManager.uint32_type)
+ other = l;
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type)){
+ left = ForceConversion (ec, left, TypeManager.int64_type);
+ right = ForceConversion (ec, right, TypeManager.int64_type);
+ type = TypeManager.int64_type;
+ } else {
+ //
+ // if either operand is of type uint, the other
+ // operand is converd to type uint
+ //
+ left = ForceConversion (ec, left, TypeManager.uint32_type);
+ right = ForceConversion (ec, right, TypeManager.uint32_type);
+ type = TypeManager.uint32_type;
+ }
+ } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
+ if (l != TypeManager.decimal_type)
+ left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
+ if (r != TypeManager.decimal_type)
+ right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
+
+ type = TypeManager.decimal_type;
+ } else {
+ Expression l_tmp, r_tmp;
+
+ l_tmp = ForceConversion (ec, left, TypeManager.int32_type);
+ if (l_tmp == null)
+ return false;
+
+ r_tmp = ForceConversion (ec, right, TypeManager.int32_type);
+ if (r_tmp == null)
+ return false;
+
+ left = l_tmp;
+ right = r_tmp;
+
+ type = TypeManager.int32_type;
+ }
+
+ return true;
+ }
+
+ void error19 ()
+ {
+ Error (19, loc,
+ "Operator " + OperName () + " cannot be applied to operands of type `" +
+ TypeManager.CSharpName (left.Type) + "' and `" +
+ TypeManager.CSharpName (right.Type) + "'");
+
+ }
+
+ Expression CheckShiftArguments (EmitContext ec)
+ {
+ Expression e;
+ Type l = left.Type;
+ Type r = right.Type;
+
+ e = ForceConversion (ec, right, TypeManager.int32_type);
+ if (e == null){
+ error19 ();
+ return null;
+ }
+ right = e;
+
+ if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
+ left = e;
+ type = e.Type;
+
+ return this;
+ }
+ error19 ();
+ return null;
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type l = left.Type;
+ Type r = right.Type;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression left_expr, right_expr;
+
+ string op = "op_" + oper;
+
+ left_expr = MemberLookup (ec, l, op, false, loc);
+ if (left_expr == null && l.BaseType != null)
+ left_expr = MemberLookup (ec, l.BaseType, op, false, loc);
+
+ right_expr = MemberLookup (ec, r, op, false, loc);
+ if (right_expr == null && r.BaseType != null)
+ right_expr = MemberLookup (ec, r.BaseType, op, false, loc);
+
+ MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr);
+
+ if (union != null) {
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ method = Invocation.OverloadResolve (ec, union, Arguments, loc);
+ if (method != null) {
+ MethodInfo mi = (MethodInfo) method;
+ type = mi.ReturnType;
+ return this;
+ } else {
+ error19 ();
+ return null;
+ }
+ }
+
+ //
+ // Step 2: Default operations on CLI native types.
+ //
+
+ // Only perform numeric promotions on:
+ // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
+ //
+ if (oper == Operator.Addition){
+ //
+ // If any of the arguments is a string, cast to string
+ //
+ if (l == TypeManager.string_type){
+ if (r == TypeManager.string_type){
+ if (left is Literal && right is Literal){
+ StringLiteral ls = (StringLiteral) left;
+ StringLiteral rs = (StringLiteral) right;
+
+ return new StringLiteral (ls.Value + rs.Value);
+ }
+
+ // string + string
+ method = TypeManager.string_concat_string_string;
+ } else {
+ // string + object
+ method = TypeManager.string_concat_object_object;
+ right = ConvertImplicit (ec, right,
+ TypeManager.object_type, loc);
+ }
+ type = TypeManager.string_type;
+
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ return this;
+
+ } else if (r == TypeManager.string_type){
+ // object + string
+ method = TypeManager.string_concat_object_object;
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
+ type = TypeManager.string_type;
+
+ return this;
+ }
+
+ //
+ // FIXME: is Delegate operator + (D x, D y) handled?
+ //
+ }
+
+ if (oper == Operator.LeftShift || oper == Operator.RightShift)
+ return CheckShiftArguments (ec);
+
+ if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
+ if (l != TypeManager.bool_type || r != TypeManager.bool_type){
+ error19 ();
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ if (l == TypeManager.bool_type || r == TypeManager.bool_type){
+ if (r != TypeManager.bool_type || l != TypeManager.bool_type){
+ error19 ();
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ }
+
+ //
+ // We are dealing with numbers
+ //
+
+ if (!DoNumericPromotions (ec, l, r)){
+ // Attempt:
+ //
+ // operator != (object a, object b)
+ // operator == (object a, object b)
+ //
+
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ Expression li, ri;
+ li = ConvertImplicit (ec, left, TypeManager.object_type, loc);
+ if (li != null){
+ ri = ConvertImplicit (ec, right, TypeManager.object_type,
+ loc);
+ if (ri != null){
+ left = li;
+ right = ri;
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+ }
+ }
+
+ error19 ();
+ return null;
+ }
+
+ if (left == null || right == null)
+ return null;
+
+
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ if (!((l == TypeManager.int32_type) ||
+ (l == TypeManager.uint32_type) ||
+ (l == TypeManager.int64_type) ||
+ (l == TypeManager.uint64_type))){
+ error19 ();
+ return null;
+ }
+ type = l;
+ }
+
+ if (oper == Operator.Equality ||
+ oper == Operator.Inequality ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.LessThan ||
+ oper == Operator.GreaterThanOrEqual ||
+ oper == Operator.GreaterThan){
+ type = TypeManager.bool_type;
+ }
+
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ left = left.Resolve (ec);
+ right = right.Resolve (ec);
+
+ if (left == null || right == null)
+ return null;
+
+ if (left.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ left + ") at Line: " + loc.Row);
+ if (right.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ right + ") at Line: "+ loc.Row);
+
+ eclass = ExprClass.Value;
+
+ return ResolveOperator (ec);
+ }
+
+ public bool IsBranchable ()