📄 expression.cs
字号:
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 (); } public override string ToString () { return "operator " + OperName (oper) + "(" + left.ToString () + ", " + right.ToString () + ")"; } Expression ForceConversion (EmitContext ec, Expression expr, Type target_type) { if (expr.Type == target_type) return expr; return Convert.ImplicitConversion (ec, expr, target_type, loc); } public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r) { Report.Error ( 34, loc, "Operator `" + OperName (oper) + "' is ambiguous on operands of type `" + TypeManager.CSharpName (l) + "' " + "and `" + TypeManager.CSharpName (r) + "'"); } bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions) { if ((l == t) || (r == t)) return true; if (!check_user_conversions) return false; if (Convert.ImplicitUserConversionExists (ec, l, t)) return true; else if (Convert.ImplicitUserConversionExists (ec, r, t)) return true; else return false; } // // Note that handling the case l == Decimal || r == Decimal // is taken care of by the Step 1 Operator Overload resolution. // // If `check_user_conv' is true, we also check whether a user-defined conversion // exists. Note that we only need to do this if both arguments are of a user-defined // type, otherwise ConvertImplict() already finds the user-defined conversion for us, // so we don't explicitly check for performance reasons. // bool DoNumericPromotions (EmitContext ec, Type l, Type r, Expression lexpr, Expression rexpr, bool check_user_conv) { if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){ // // If either operand is of type double, the other operand is // conveted to type double. // if (r != TypeManager.double_type) right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc); if (l != TypeManager.double_type) left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc); type = TypeManager.double_type; } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){ // // if either operand is of type float, the other operand is // converted to type float. // if (r != TypeManager.double_type) right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc); if (l != TypeManager.double_type) left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc); type = TypeManager.float_type; } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){ 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){ if (right is IntConstant){ IntConstant ic = (IntConstant) right; e = Convert.TryImplicitIntConversion (l, ic); if (e != null) right = e; } else if (right is LongConstant){ long ll = ((LongConstant) right).Value; if (ll >= 0) right = new ULongConstant ((ulong) ll, right.Location); } else { e = Convert.ImplicitNumericConversion (ec, right, l); if (e != null) right = e; } } other = right.Type; } else { if (left is IntConstant){ e = Convert.TryImplicitIntConversion (r, (IntConstant) left); if (e != null) left = e; } else if (left is LongConstant){ long ll = ((LongConstant) left).Value; if (ll > 0) left = new ULongConstant ((ulong) ll, right.Location); } else { e = Convert.ImplicitNumericConversion (ec, left, r); 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)) Error_OperatorAmbiguous (loc, oper, l, r); else { left = ForceConversion (ec, left, TypeManager.uint64_type); right = ForceConversion (ec, right, TypeManager.uint64_type); } type = TypeManager.uint64_type; } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){ // // If either operand is of type long, the other operand is converted // to type long. // if (l != TypeManager.int64_type) left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc); if (r != TypeManager.int64_type) right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc); type = TypeManager.int64_type; } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){ // // 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 (unless we have an int constant). // Type other = null; if (l == TypeManager.uint32_type){ if (right is IntConstant){ IntConstant ic = (IntConstant) right; int val = ic.Value; if (val >= 0){ right = new UIntConstant ((uint) val, ic.Location); type = l; return true; } } other = r; } else if (r == TypeManager.uint32_type){ if (left is IntConstant){ IntConstant ic = (IntConstant) left; int val = ic.Value; if (val >= 0){ left = new UIntConstant ((uint) val, ic.Location); type = r; return true; } } 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 = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc); if (r != TypeManager.decimal_type) right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc); type = TypeManager.decimal_type; } else { left = ForceConversion (ec, left, TypeManager.int32_type); right = ForceConversion (ec, right, TypeManager.int32_type); bool strConv = Convert.ImplicitConversionExists (ec, lexpr, TypeManager.string_type) && Convert.ImplicitConversionExists (ec, rexpr, TypeManager.string_type); if (strConv && left != null && right != null) Error_OperatorAmbiguous (loc, oper, l, r); type = TypeManager.int32_type; } return (left != null) && (right != null); } static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r) { Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r)); } public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right) { Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'", name, left, right); } void Error_OperatorCannotBeApplied () { Error_OperatorCannotBeApplied (Location, OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ()); } static bool is_unsigned (Type t) { return (t == TypeManager.uint32_type || t == TypeManager.uint64_type || t == TypeManager.short_type || t == TypeManager.byte_type); } static bool is_user_defined (Type t) { if (t.IsSubclassOf (TypeManager.value_type) && (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type)) return true; else return false; } Expression Make32or64 (EmitContext ec, Expression e) { Type t= e.Type; if (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type || t == TypeManager.uint64_type) return e; Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc); if (ee != null) return ee; ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc); if (ee != null) return ee; ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc); if (ee != null) return ee; ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc); if (ee != null) return ee; return null; } Expression CheckShiftArguments (EmitContext ec) { Expression e; e = ForceConversion (ec, right, TypeManager.int32_type); if (e == null){ Error_OperatorCannotBeApplied (); return null; } right = e; if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) || ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) || ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) || ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){ left = e; type = e.Type; if (type == TypeManager.int32_type || type == TypeManager.uint32_type){ right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (31, loc)); right = right.DoResolve (ec); } else { right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (63, loc)); right = right.DoResolve (ec); } return this; } Error_OperatorCannotBeApplied (); return null; } // // This is used to check if a test 'x == null' can be optimized to a reference equals, // i.e., not invoke op_Equality. // static bool EqualsNullIsReferenceEquals (Type t) { return t == TypeManager.object_type || t == TypeManager.string_type || t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type); } static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type) { Report.Warning ((side == "left" ? 252 : 253), 2, loc, "Possible unintended reference comparison; to get a value comparison, " + "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type)); } Expression ResolveOperator (EmitContext ec) { Type l = left.Type; Type r = right.Type; if (oper == Operator.Equality || oper == Operator.Inequality){ // // Optimize out call to op_Equality in a few cases. // if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) || (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) { Type = TypeManager.bool_type; return this; } // IntPtr equality if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) { Type = TypeManager.bool_type; return this; } } // // Do not perform operator overload resolution when both sides are // built-in types // Expression left_operators = null, right_operators = null; if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){ // // Step 1: Perform Operator Overload location // string op = oper_names [(int) oper]; MethodGroupExpr union; left_operators = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc); if (r != l){ right_operators = MemberLookup ( ec, r, op, MemberTypes.Method, AllBindingFlags, loc); union = Invocation.MakeUnionSet (left_operators, right_operators, loc); } else union = (MethodGroupExpr) left_operators; if (union != null) { ArrayList args = new ArrayList (2); args.Add (new Argument (left, Argument.AType.Expression)); args.Add (new Argument (right, Argument.AType.Expression)); MethodBase method = Invocation.OverloadResolve ( ec, union, args, true, Location.Null); if (method != null) { MethodInfo mi = (MethodInfo) method; return new BinaryMethod (mi.ReturnType, method, args); } } } // // Step 0: String concatenation (because overloading will get this wrong) // if (oper == Operator.Addition){ // // If any of the arguments is a string, cast 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 (r == TypeManager.void_type || l == TypeManager.void_type) { Error_OperatorCannotBeApplied (); return null; } // try to fold it in on the left if (left is StringConcat) { // // 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; } } // Otherwise, start a new concat expression return new StringConcat (ec, loc, left, right).Resolve (ec); } // // Transform a + ( - b) into a - b // if (right is Unary){ Unary right_unary = (Unary) right; if (right_unary.Oper == Unary.Operator.UnaryNegation){ oper = Operator.Subtraction; right = right_unary.Expr; r = right.Type; } } } 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){ Error_OperatorCannotBeApplied (); return null; } type = TypeManager.bool_type; return this; } if (l.IsPointer || r.IsPointer) { if (l.IsPointer && r.IsPointer) { type = TypeManager.bool_type; return this; } if (l.IsPointer && r == TypeManager.null_type) { right = new EmptyCast (NullPointer.Null, l); type = TypeManager.bool_type; return this; } if (r.IsPointer && l == TypeManager.null_type) { left = new EmptyCast (NullPointer.Null, r); type = TypeManager.bool_type; return this; } } // // operator != (object a, object b) // operator == (object a, object b)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -