?? expression.cs
字號:
// // For this to be used, both arguments have to be reference-types. // Read the rationale on the spec (14.9.6) // if (!(l.IsValueType || r.IsValueType)){ type = TypeManager.bool_type; if (l == r) return this; // // Also, a standard conversion must exist from either one // bool left_to_right = Convert.ImplicitStandardConversionExists (ec, left, r); bool right_to_left = !left_to_right && Convert.ImplicitStandardConversionExists (ec, right, l); if (!left_to_right && !right_to_left) { Error_OperatorCannotBeApplied (); return null; } if (left_to_right && left_operators != null && RootContext.WarningLevel >= 2) { ArrayList args = new ArrayList (2); args.Add (new Argument (left, Argument.AType.Expression)); args.Add (new Argument (left, Argument.AType.Expression)); MethodBase method = Invocation.OverloadResolve ( ec, (MethodGroupExpr) left_operators, args, true, Location.Null); if (method != null) Warning_UnintendedReferenceComparison (loc, "right", l); } if (right_to_left && right_operators != null && RootContext.WarningLevel >= 2) { ArrayList args = new ArrayList (2); args.Add (new Argument (right, Argument.AType.Expression)); args.Add (new Argument (right, Argument.AType.Expression)); MethodBase method = Invocation.OverloadResolve ( ec, (MethodGroupExpr) right_operators, args, true, Location.Null); if (method != null) Warning_UnintendedReferenceComparison (loc, "left", r); } // // We are going to have to convert to an object to compare // if (l != TypeManager.object_type) left = new EmptyCast (left, TypeManager.object_type); if (r != TypeManager.object_type) right = new EmptyCast (right, TypeManager.object_type); // // FIXME: CSC here catches errors cs254 and cs252 // return this; } // // One of them is a valuetype, but the other one is not. // if (!l.IsValueType || !r.IsValueType) { Error_OperatorCannotBeApplied (); return null; } } // Only perform numeric promotions on: // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >= // if (oper == Operator.Addition || oper == Operator.Subtraction) { if (l.IsSubclassOf (TypeManager.delegate_type)){ if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))){ if ((RootContext.Version != LanguageVersion.ISO_1)){ Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc); if (tmp == null) return null; right = tmp; r = right.Type; } } if (r.IsSubclassOf (TypeManager.delegate_type)){ MethodInfo method; ArrayList args = new ArrayList (2); args = new ArrayList (2); args.Add (new Argument (left, Argument.AType.Expression)); args.Add (new Argument (right, Argument.AType.Expression)); if (oper == Operator.Addition) method = TypeManager.delegate_combine_delegate_delegate; else method = TypeManager.delegate_remove_delegate_delegate; if (l != r) { Error_OperatorCannotBeApplied (); return null; } return new BinaryDelegate (l, method, args); } } // // Pointer arithmetic: // // T* operator + (T* x, int y); // T* operator + (T* x, uint y); // T* operator + (T* x, long y); // T* operator + (T* x, ulong y); // // T* operator + (int y, T* x); // T* operator + (uint y, T *x); // T* operator + (long y, T *x); // T* operator + (ulong y, T *x); // // T* operator - (T* x, int y); // T* operator - (T* x, uint y); // T* operator - (T* x, long y); // T* operator - (T* x, ulong y); // // long operator - (T* x, T *y) // if (l.IsPointer){ if (r.IsPointer && oper == Operator.Subtraction){ if (r == l) return new PointerArithmetic ( false, left, right, TypeManager.int64_type, loc).Resolve (ec); } else { Expression t = Make32or64 (ec, right); if (t != null) return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec); } } else if (r.IsPointer && oper == Operator.Addition){ Expression t = Make32or64 (ec, left); if (t != null) return new PointerArithmetic (true, right, t, r, loc).Resolve (ec); } } // // Enumeration operators // bool lie = TypeManager.IsEnumType (l); bool rie = TypeManager.IsEnumType (r); if (lie || rie){ Expression temp; // U operator - (E e, E f) if (lie && rie){ if (oper == Operator.Subtraction){ if (l == r){ type = TypeManager.EnumToUnderlying (l); return this; } Error_OperatorCannotBeApplied (); return null; } } // // operator + (E e, U x) // operator - (E e, U x) // if (oper == Operator.Addition || oper == Operator.Subtraction){ Type enum_type = lie ? l : r; Type other_type = lie ? r : l; Type underlying_type = TypeManager.EnumToUnderlying (enum_type); if (underlying_type != other_type){ temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc); if (temp != null){ if (lie) right = temp; else left = temp; type = enum_type; return this; } Error_OperatorCannotBeApplied (); return null; } type = enum_type; return this; } if (!rie){ temp = Convert.ImplicitConversion (ec, right, l, loc); if (temp != null) right = temp; else { Error_OperatorCannotBeApplied (); return null; } } if (!lie){ temp = Convert.ImplicitConversion (ec, left, r, loc); if (temp != null){ left = temp; l = r; } else { Error_OperatorCannotBeApplied (); return null; } } if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.LessThanOrEqual || oper == Operator.LessThan || oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){ if (left.Type != right.Type){ Error_OperatorCannotBeApplied (); return null; } type = TypeManager.bool_type; return this; } if (oper == Operator.BitwiseAnd || oper == Operator.BitwiseOr || oper == Operator.ExclusiveOr){ if (left.Type != right.Type){ Error_OperatorCannotBeApplied (); return null; } type = l; return this; } Error_OperatorCannotBeApplied (); return null; } 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) { type = TypeManager.bool_type; return this; } if (l != r) { Error_OperatorCannotBeApplied (); return null; } Expression e = new ConditionalLogicalOperator ( oper == Operator.LogicalAnd, left, right, l, loc); return e.Resolve (ec); } // // operator & (bool x, bool y) // operator | (bool x, bool y) // operator ^ (bool x, bool y) // if (l == TypeManager.bool_type && r == TypeManager.bool_type){ if (oper == Operator.BitwiseAnd || oper == Operator.BitwiseOr || oper == Operator.ExclusiveOr){ type = l; return this; } } // // Pointer comparison // if (l.IsPointer && r.IsPointer){ if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual || oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){ type = TypeManager.bool_type; return this; } } // // This will leave left or right set to null if there is an error // bool check_user_conv = is_user_defined (l) && is_user_defined (r); DoNumericPromotions (ec, l, r, left, right, check_user_conv); if (left == null || right == null){ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r); return null; } // // reload our cached types if required // l = left.Type; r = right.Type; if (oper == Operator.BitwiseAnd || oper == Operator.BitwiseOr || oper == Operator.ExclusiveOr){ if (l == r){ if (((l == TypeManager.int32_type) || (l == TypeManager.uint32_type) || (l == TypeManager.short_type) || (l == TypeManager.ushort_type) || (l == TypeManager.int64_type) || (l == TypeManager.uint64_type))){ type = l; } else { Error_OperatorCannotBeApplied (); return null; } } else { Error_OperatorCannotBeApplied (); return null; } } 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; } Constant EnumLiftUp (EmitContext ec, Constant left, Constant right) { switch (oper) { case Operator.BitwiseOr: case Operator.BitwiseAnd: case Operator.ExclusiveOr: case Operator.Equality: case Operator.Inequality: case Operator.LessThan: case Operator.LessThanOrEqual: case Operator.GreaterThan: case Operator.GreaterThanOrEqual: if (left is EnumConstant) return left; if (left.IsZeroInteger) return new EnumConstant (left, right.Type); break; case Operator.Addition: case Operator.Subtraction: return left; case Operator.Multiply: case Operator.Division: case Operator.Modulus: case Operator.LeftShift: case Operator.RightShift: if (right is EnumConstant || left is EnumConstant) break; return left; } Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type); return null; } public override Expression DoResolve (EmitContext ec) { if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) { left = ((ParenthesizedExpression) left).Expr; left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type); if (left == null) return null; if (left.eclass == ExprClass.Type) { Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses"); return null; } } else left = left.Resolve (ec); if (left == null) return null; Constant lc = left as Constant; if (lc != null && lc.Type == TypeManager.bool_type && ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) || (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) { // TODO: make a sense to resolve unreachable expression as we do for statement Report.Warning (429, 4, loc, "Unreachable expression code detected"); return left; } right = right.Resolve (ec); if (right == null) return null; eclass = ExprClass.Value; Constant rc = right as Constant; // 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); if (lc == null) return null; right = rc = EnumLiftUp (ec, rc, lc); if (rc == null) return null; } if (oper == Operator.BitwiseAnd) { if (rc != null && rc.IsZeroInteger) { return lc is EnumConstant ? new EnumConstant (rc, lc.Type): rc; } if (lc != null && lc.IsZeroInteger) { return rc is EnumConstant ? new EnumConstant (lc, rc.Type): lc; } } else if (oper == Operator.BitwiseOr) { if (lc is EnumConstant && rc != null && rc.IsZeroInteger) return lc; if (rc is EnumConstant && lc != null && lc.IsZeroInteger) return rc; } else if (oper == Operator.LogicalAnd) { if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type) return rc; if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type) return lc; } if (rc != null && lc != null){ int prev_e = Report.Errors; Expression e = ConstantFold.BinaryFold ( ec, oper, lc, rc, loc); if (e != null || Report.Errors != prev_e) return e; } // Comparison warnings if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.LessThanOrEqual || oper == Operator.LessThan || oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){ if (left.Equals (right)) { Report.Warning (1718, 3, loc, "Comparison made to same variable; did you mean to compare something else?"); } CheckUselessComparison (lc, right.Type); CheckUselessComparison (rc, left.Type); } return ResolveOperator (ec); } private void CheckUselessComparison (Constant c, Type type) { if (c == null || !IsTypeIntegral (type) || c is StringConstant || c is BoolConstant || c is CharConstant || c is FloatConstant || c is DoubleConstant || c is DecimalConstant ) return; long value = 0; if (c is ULongConstant) { ulong uvalue = ((ULongConstant) c).Value; if (uvalue > long.MaxValue) { if (type == TypeManager.byte_type || type == TypeManager.sbyte_type || type == TypeManager.short_type ||
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -