Expression ResolveOperator (ResolveContext ec) { type = expr.Type; // // The operand of the prefix/postfix increment decrement operators // should be an expression that is classified as a variable, // a property access or an indexer access // if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) { expr = expr.ResolveLValue (ec, expr); } else { ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer"); } // // Step 1: Perform Operator Overload location // MethodGroupExpr mg; string op_name; if (mode == Mode.PreIncrement || mode == Mode.PostIncrement) op_name = Operator.GetMetadataName (Operator.OpType.Increment); else op_name = Operator.GetMetadataName (Operator.OpType.Decrement); mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr; if (mg != null) { Arguments args = new Arguments (1); args.Add (new Argument (expr)); mg = mg.OverloadResolve (ec, ref args, false, loc); if (mg == null) return null; method = new UserOperatorCall (mg, args, null, loc); Convert.ImplicitConversionRequired (ec, method, type, loc); return this; } if (!IsIncrementableNumber (type)) { ec.Report.Error (187, loc, "No such operator '" + OperName (mode) + "' defined for type '" + TypeManager.CSharpName (type) + "'"); return null; } return this; }
// // Performs user-operator overloading // protected virtual Expression ResolveUserOperator (ResolveContext ec, Type l, Type r) { Operator user_oper; if (oper == Operator.LogicalAnd) user_oper = Operator.BitwiseAnd; else if (oper == Operator.LogicalOr) user_oper = Operator.BitwiseOr; else user_oper = oper; string op = GetOperatorMetadataName (user_oper); MethodGroupExpr left_operators = MemberLookup (ec.Compiler, ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr; MethodGroupExpr right_operators = null; if (!TypeManager.IsEqual (r, l)) { right_operators = MemberLookup (ec.Compiler, ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr; if (right_operators == null && left_operators == null) return null; } else if (left_operators == null) { return null; } Arguments args = new Arguments (2); Argument larg = new Argument (left); args.Add (larg); Argument rarg = new Argument (right); args.Add (rarg); MethodGroupExpr union; // // User-defined operator implementations always take precedence // over predefined operator implementations // if (left_operators != null && right_operators != null) { if (IsPredefinedUserOperator (l, user_oper)) { union = right_operators.OverloadResolve (ec, ref args, true, loc); if (union == null) union = left_operators; } else if (IsPredefinedUserOperator (r, user_oper)) { union = left_operators.OverloadResolve (ec, ref args, true, loc); if (union == null) union = right_operators; } else { union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc); } } else if (left_operators != null) { union = left_operators; } else { union = right_operators; } union = union.OverloadResolve (ec, ref args, true, loc); if (union == null) return null; Expression oper_expr; // TODO: CreateExpressionTree is allocated every time if (user_oper != oper) { oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree, oper == Operator.LogicalAnd, loc).Resolve (ec); } else { oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc); // // This is used to check if a test 'x == null' can be optimized to a reference equals, // and not invoke user operator // if ((oper & Operator.EqualityMask) != 0) { if ((left is NullLiteral && IsBuildInEqualityOperator (r)) || (right is NullLiteral && IsBuildInEqualityOperator (l))) { type = TypeManager.bool_type; if (left is NullLiteral || right is NullLiteral) oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec); } else if (l != r) { MethodInfo mi = (MethodInfo) union; // // Two System.Delegate(s) are never equal // if (mi.DeclaringType == TypeManager.multicast_delegate_type) return null; } } } left = larg.Expr; right = rarg.Expr; return oper_expr; }