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