//
		// 7.9.6 Reference type equality operators
		//
		Binary ResolveOperatorEqualityRerefence (ResolveContext ec, Type l, Type r)
		{
			//
			// operator != (object a, object b)
			// operator == (object a, object b)
			//

			// TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion

			if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
				return null;

			type = TypeManager.bool_type;
			GenericConstraints constraints;

			bool lgen = TypeManager.IsGenericParameter (l);

			if (TypeManager.IsEqual (l, r)) {
				if (lgen) {
					//
					// Only allow to compare same reference type parameter
					//
					if (TypeManager.IsReferenceType (l)) {
						left = new BoxedCast (left, TypeManager.object_type);
						right = new BoxedCast (right, TypeManager.object_type);
						return this;
					}

					return null;
				}

				if (l == InternalType.AnonymousMethod)
					return null;

				if (TypeManager.IsValueType (l))
					return null;

				return this;
			}

			bool rgen = TypeManager.IsGenericParameter (r);

			//
			// a, Both operands are reference-type values or the value null
			// b, One operand is a value of type T where T is a type-parameter and
			// the other operand is the value null. Furthermore T does not have the
			// value type constrain
			//
			if (left is NullLiteral || right is NullLiteral) {
				if (lgen) {
					constraints = TypeManager.GetTypeParameterConstraints (l);
					if (constraints != null && constraints.HasValueTypeConstraint)
						return null;

					left = new BoxedCast (left, TypeManager.object_type);
					return this;
				}

				if (rgen) {
					constraints = TypeManager.GetTypeParameterConstraints (r);
					if (constraints != null && constraints.HasValueTypeConstraint)
						return null;

					right = new BoxedCast (right, TypeManager.object_type);
					return this;
				}
			}

			//
			// An interface is converted to the object before the
			// standard conversion is applied. It's not clear from the
			// standard but it looks like it works like that.
			//
			if (lgen) {
				if (!TypeManager.IsReferenceType (l))
					return null;

				l = TypeManager.object_type;
				left = new BoxedCast (left, l);
			} else if (l.IsInterface) {
				l = TypeManager.object_type;
			} else if (TypeManager.IsStruct (l)) {
				return null;
			}

			if (rgen) {
				if (!TypeManager.IsReferenceType (r))
					return null;

				r = TypeManager.object_type;
				right = new BoxedCast (right, r);
			} else if (r.IsInterface) {
				r = TypeManager.object_type;
			} else if (TypeManager.IsStruct (r)) {
				return null;
			}


			const string ref_comparison = "Possible unintended reference comparison. " +
				"Consider casting the {0} side of the expression to `string' to compare the values";

			//
			// A standard implicit conversion exists from the type of either
			// operand to the type of the other operand
			//
			if (Convert.ImplicitReferenceConversionExists (left, r)) {
				if (l == TypeManager.string_type)
					ec.Report.Warning (253, 2, loc, ref_comparison, "right");

				return this;
			}

			if (Convert.ImplicitReferenceConversionExists (right, l)) {
				if (r == TypeManager.string_type)
					ec.Report.Warning (252, 2, loc, ref_comparison, "left");

				return this;
			}

			return null;
		}
		Expression ResolveGenericParameter (ResolveContext ec, Type d, Type t)
		{
			GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
			if (constraints != null) {
				if (constraints.IsReferenceType && TypeManager.IsStruct (d))
					return CreateConstantResult (ec, false);
			}

			if (TypeManager.IsGenericParameter (expr.Type)) {
				if (constraints != null && constraints.IsValueType && expr.Type == t)
					return CreateConstantResult (ec, true);

				expr = new BoxedCast (expr, d);
			}

			return this;
		}
		public override Expression DoResolve (ResolveContext ec)
		{
			// Because expr is modified
			if (eclass != ExprClass.Invalid)
				return this;

			if (resolved_type == null) {
				resolved_type = base.DoResolve (ec);

				if (resolved_type == null)
					return null;
			}

			type = probe_type_expr.Type;
			eclass = ExprClass.Value;
			Type etype = expr.Type;

			if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
				if (TypeManager.IsGenericParameter (type)) {
					ec.Report.Error (413, loc,
						"The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
						probe_type_expr.GetSignatureForError ());
				} else {
					ec.Report.Error (77, loc,
						"The `as' operator cannot be used with a non-nullable value type `{0}'",
						TypeManager.CSharpName (type));
				}
				return null;
			}

			if (expr.IsNull && TypeManager.IsNullableType (type)) {
				return Nullable.LiftedNull.CreateFromExpression (ec, this);
			}
			
			Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
			if (e != null){
				expr = e;
				do_isinst = false;
				return this;
			}

			if (Convert.ExplicitReferenceConversionExists (etype, type)){
				if (TypeManager.IsGenericParameter (etype))
					expr = new BoxedCast (expr, etype);

				do_isinst = true;
				return this;
			}

			if (TypeManager.ContainsGenericParameters (etype) ||
			    TypeManager.ContainsGenericParameters (type)) {
				expr = new BoxedCast (expr, etype);
				do_isinst = true;
				return this;
			}

			ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
				TypeManager.CSharpName (etype), TypeManager.CSharpName (type));

			return null;
		}
Exemple #4
0
		Expression ResolveGenericParameter (Type d, Type t)
		{
#if GMCS_SOURCE
			GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
			if (constraints != null) {
				if (constraints.IsReferenceType && d.IsValueType)
					return CreateConstantResult (false);

				if (constraints.IsValueType && !d.IsValueType)
					return CreateConstantResult (TypeManager.IsEqual (d, t));
			}

			if (!TypeManager.IsReferenceType (expr.Type))
				expr = new BoxedCast (expr, d);

			return this;
#else
			return null;
#endif
		}