Expression AssertBoolContext(Expression expression) { var type = GetExpressionType(expression); if (TypeSystemServices.IsNumberOrBool(type) || type.IsEnum) { return(expression); } var op_Implicit = TypeSystemServices.FindImplicitConversionOperator(type, TypeSystemServices.BoolType); if (op_Implicit != null) { //return [| $op_Implicit($expression) |] return(CodeBuilder.CreateMethodInvocation(op_Implicit, expression)); } // nullable types can be used in bool context if (TypeSystemServices.IsNullable(type)) { //return [| $(expression).HasValue |] return(CodeBuilder.CreateMethodInvocation(expression, NameResolutionService.ResolveMethod(type, "get_HasValue"))); } // string in a boolean context means string.IsNullOrEmpty (BOO-1035) if (TypeSystemServices.StringType == type) { //return [| not string.IsNullOrEmpty($expression) |] var notIsNullOrEmpty = new UnaryExpression( UnaryOperatorType.LogicalNot, CodeBuilder.CreateMethodInvocation(String_IsNullOrEmpty, expression)); BindExpressionType(notIsNullOrEmpty, TypeSystemServices.BoolType); return(notIsNullOrEmpty); } // reference types can be used in bool context if (!type.IsValueType) { return(expression); } Error(CompilerErrorFactory.BoolExpressionRequired(expression, type.ToString())); return(expression); }
public bool AssertTypeCompatibility(Node sourceNode, IType expectedType, IType actualType) { if (IsError(expectedType) || IsError(actualType)) { return(false); } if (expectedType.IsPointer && actualType.IsPointer) { return(true); //if both types are unmanaged pointers casting is always possible } if (TypeSystemServices.IsNullable(expectedType) && actualType.IsNull()) { return(true); } if (!CanBeReachedFrom(sourceNode, expectedType, actualType)) { _errors.Instance.Add(CompilerErrorFactory.IncompatibleExpressionType(sourceNode, expectedType, actualType)); return(false); } return(true); }