Expression ConvertExpression(ResolveContext ec)
{
// TODO: ImplicitConversionExists should take care of this
if (left.eclass == ExprClass.MethodGroup)
{
return(null);
}
TypeSpec ltype = left.Type;
//
// If left is a nullable type and an implicit conversion exists from right to underlying type of left,
// the result is underlying type of left
//
if (ltype.IsNullableType)
{
unwrap = Unwrap.Create(left, false);
if (unwrap == null)
{
return(null);
}
//
// Reduce (left ?? null) to left
//
if (right.IsNull)
{
return(ReducedExpression.Create(left, this));
}
Expression conv;
if (right.Type.IsNullableType)
{
conv = right.Type == ltype ? right : Convert.ImplicitNulableConversion(ec, right, ltype);
if (conv != null)
{
right = conv;
type = ltype;
return(this);
}
}
else
{
conv = Convert.ImplicitConversion(ec, right, unwrap.Type, loc);
if (conv != null)
{
left = unwrap;
ltype = left.Type;
//
// If right is a dynamic expression, the result type is dynamic
//
if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
{
type = right.Type;
// Need to box underlying value type
left = Convert.ImplicitBoxingConversion(left, ltype, type);
return(this);
}
right = conv;
type = ltype;
return(this);
}
}
}
else if (TypeSpec.IsReferenceType(ltype))
{
if (Convert.ImplicitConversionExists(ec, right, ltype))
{
//
// If right is a dynamic expression, the result type is dynamic
//
if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
{
type = right.Type;
return(this);
}
//
// Reduce ("foo" ?? expr) to expression
//
Constant lc = left as Constant;
if (lc != null && !lc.IsDefaultValue)
{
return(ReducedExpression.Create(lc, this, false));
}
//
// Reduce (left ?? null) to left OR (null-constant ?? right) to right
//
if (right.IsNull || lc != null)
{
//
// Special case null ?? null
//
if (right.IsNull && ltype == right.Type)
{
return(null);
}
return(ReducedExpression.Create(lc != null ? right : left, this, false));
}
right = Convert.ImplicitConversion(ec, right, ltype, loc);
type = ltype;
return(this);
}
}
else
{
return(null);
}
TypeSpec rtype = right.Type;
if (!Convert.ImplicitConversionExists(ec, unwrap ?? left, rtype) || right.eclass == ExprClass.MethodGroup)
{
return(null);
}
//
// Reduce (null ?? right) to right
//
if (left.IsNull)
{
return(ReducedExpression.Create(right, this, false).Resolve(ec));
}
left = Convert.ImplicitConversion(ec, unwrap ?? left, rtype, loc);
type = rtype;
return(this);
}