Ejemplo n.º 1
0
 public void CastDynamicArgs(ResolveContext rc)
 {
     for (int i = 0; i < args.Count; ++i)
     {
         Argument a = args[i];
         // remove dynamic
         a.Expr = EmptyCast.RemoveDynamic(rc, a.Expr);
     }
 }
Ejemplo n.º 2
0
 protected override Expression ResolveConversions(ResolveContext ec)
 {
     source = EmptyCast.Create(source, target.Type);
     return(this);
 }
Ejemplo n.º 3
0
		Expression ResolveOperator (EmitContext ec)
		{
			Type l = left.Type;
			Type r = right.Type;

			bool overload_failed = false;

			//
			// Special cases: string comapred to null
			//
			if (oper == Operator.Equality || oper == Operator.Inequality){
				if ((l == TypeManager.string_type && (right is NullLiteral)) ||
				    (r == TypeManager.string_type && (left is NullLiteral))){
					Type = TypeManager.bool_type;
					
					return this;
				}
			}

			//
			// Do not perform operator overload resolution when both sides are
			// built-in types
			//
			if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
				//
				// Step 1: Perform Operator Overload location
				//
				Expression left_expr, right_expr;
				
				string op = oper_names [(int) oper];
				
				MethodGroupExpr union;
				left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
				if (r != l){
					right_expr = MemberLookup (
						ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
					union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
				} else
					union = (MethodGroupExpr) left_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, Location.Null);
					if (method != null) {
						MethodInfo mi = (MethodInfo) method;
						
						type = mi.ReturnType;
						return this;
					} else {
						overload_failed = true;
					}
				}
			}
			
			//
			// Step 2: Default operations on CLI native types.
			//

			//
			// 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
				//
				
				if (l == TypeManager.string_type){
					
					if (r == TypeManager.void_type) {
						Error_OperatorCannotBeApplied ();
						return null;
					}
					
					if (r == TypeManager.string_type){
						if (left is Constant && right is Constant){
							StringConstant ls = (StringConstant) left;
							StringConstant rs = (StringConstant) right;
							
							return new StringConstant (
								ls.Value + rs.Value);
						}

						if (left is Binary){
							Binary b = (Binary) left;

							//
							// Call String.Concat (string, string, string) or
							// String.Concat (string, string, string, string)
							// if possible.
							//
							if (b.oper == Operator.Addition &&
							    (b.method == TypeManager.string_concat_string_string_string ||
							     b.method == TypeManager.string_concat_string_string_string_string)){
								ArrayList bargs = b.Arguments;
								int count = bargs.Count;
								
								if (count == 2){
									Arguments = bargs;
									Arguments.Add (new Argument (right, Argument.AType.Expression));
									type = TypeManager.string_type;
									method = TypeManager.string_concat_string_string_string;
									
									return this;
								} else if (count == 3){
									Arguments = bargs;
									Arguments.Add (new Argument (right, Argument.AType.Expression));
									type = TypeManager.string_type;
									method = TypeManager.string_concat_string_string_string_string;									
									return this;
								}
							}
						}

						// 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);
						if (right == null){
							Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
							return null;
						}
					}
					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

					if (l == TypeManager.void_type) {
						Error_OperatorCannotBeApplied ();
						return null;
					}
					
					method = TypeManager.string_concat_object_object;
					left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
					if (left == null){
						Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
						return null;
					}
					Arguments = new ArrayList ();
					Arguments.Add (new Argument (left, Argument.AType.Expression));
					Arguments.Add (new Argument (right, Argument.AType.Expression));

					type = TypeManager.string_type;

					return this;
				}

				//
				// 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;
				}

				//
				// operator != (object a, object b)
				// operator == (object a, object b)
				//
				// For this to be used, both arguments have to be reference-types.
				// Read the rationale on the spec (14.9.6)
				//
				// Also, if at compile time we know that the classes do not inherit
				// one from the other, then we catch the error there.
				//
				if (!(l.IsValueType || r.IsValueType)){
					type = TypeManager.bool_type;

					if (l == r)
						return this;
					
					if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
						return this;

					//
					// Also, a standard conversion must exist from either one
					//
					if (!(StandardConversionExists (left, r) ||
					      StandardConversionExists (right, l))){
						Error_OperatorCannotBeApplied ();
						return null;
					}
					//
					// 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) &&
				    r.IsSubclassOf (TypeManager.delegate_type)) {
					
					Arguments = new ArrayList ();
					Arguments.Add (new Argument (left, Argument.AType.Expression));
					Arguments.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;
					}

					DelegateOperation = true;
					type = l;
					return this;
				}

				//
				// 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);
					} else if (is_32_or_64 (r))
						return new PointerArithmetic (
							oper == Operator.Addition, left, right, l, loc);
				} else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
					return new PointerArithmetic (
						true, right, left, r, loc);
			}
			
			//
			// 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 && 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){
						Error_OperatorCannotBeApplied ();
						return null;
					}

					type = enum_type;
					return this;
				}
				
				if (!rie){
					temp = ConvertImplicit (ec, right, l, loc);
					if (temp != null)
						right = temp;
					else {
						Error_OperatorCannotBeApplied ();
						return null;
					}
				} if (!lie){
					temp = ConvertImplicit (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){
					type = TypeManager.bool_type;
					return this;
				}

				if (oper == Operator.BitwiseAnd ||
				    oper == Operator.BitwiseOr ||
				    oper == Operator.ExclusiveOr){
					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){
					Error_OperatorCannotBeApplied ();
					return null;
				}

				type = TypeManager.bool_type;
				return this;
			} 

			//
			// 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.Equality || oper == Operator.Inequality ||
				    oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
				    oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
					type = TypeManager.bool_type;
					return this;
				}
			}
			
			//
			// We are dealing with numbers
			//
			if (overload_failed){
				Error_OperatorCannotBeApplied ();
				return null;
			}

			//
			// 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, 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.int64_type) ||
					      (l == TypeManager.uint64_type)))
						type = l;
				} 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;
		}