internal Expression ReduceTypeEqual()
{
Type cType = Expression.Type;
if (cType.GetTypeInfo().IsValueType)
{
if (cType.IsNullableType())
{
// If the expression type is a a nullable type, it will match if
// the value is not null and the type operand
// either matches or is its type argument (T to its T?).
if (cType.GetNonNullableType() != TypeOperand.GetNonNullableType())
{
return Expression.Block(Expression, Utils.Constant(value: false));
}
else
{
return Expression.NotEqual(Expression, Expression.Constant(null, Expression.Type));
}
}
else
{
// For other value types (including Void), we can
// determine the result now
return Expression.Block(Expression, Utils.Constant(cType == TypeOperand.GetNonNullableType()));
}
}
Debug.Assert(TypeUtils.AreReferenceAssignable(typeof(object), Expression.Type), "Expecting reference types only after this point.");
// Can check the value right now for constants.
if (Expression.NodeType == ExpressionType.Constant)
{
return ReduceConstantTypeEqual();
}
// expression is a ByVal parameter. Can safely reevaluate.
var parameter = Expression as ParameterExpression;
if (parameter != null && !parameter.IsByRef)
{
return ByValParameterTypeEqual(parameter);
}
// Create a temp so we only evaluate the left side once
parameter = Expression.Parameter(typeof(object));
return Expression.Block(
new TrueReadOnlyCollection<ParameterExpression>(parameter),
new TrueReadOnlyCollection<Expression>(
Expression.Assign(parameter, Expression),
ByValParameterTypeEqual(parameter)
)
);
}