private void PrepareBoolConversionAndTruthOperator(TypeSymbol type, BinaryExpressionSyntax node, BinaryOperatorKind binaryOperator, BindingDiagnosticBag diagnostics, out BoundExpression conversionForBool, out BoundValuePlaceholder conversionForBoolPlaceholder, out UnaryOperatorSignature boolOperator) { // Is the operand implicitly convertible to bool? CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics); TypeSymbol boolean = GetSpecialType(SpecialType.System_Boolean, diagnostics, node); Conversion conversion = this.Conversions.ClassifyImplicitConversionFromType(type, boolean, ref useSiteInfo); diagnostics.Add(node, useSiteInfo); if (conversion.IsImplicit) { conversionForBoolPlaceholder = new BoundValuePlaceholder(node, type).MakeCompilerGenerated(); conversionForBool = CreateConversion(node, conversionForBoolPlaceholder, conversion, isCast: false, conversionGroupOpt: null, boolean, diagnostics); boolOperator = default; return; } // It was not. Does it implement operator true (or false)? UnaryOperatorKind boolOpKind; switch (binaryOperator) { case BinaryOperatorKind.Equal: boolOpKind = UnaryOperatorKind.False; break; case BinaryOperatorKind.NotEqual: boolOpKind = UnaryOperatorKind.True; break; default: throw ExceptionUtilities.UnexpectedValue(binaryOperator); } LookupResultKind resultKind; ImmutableArray <MethodSymbol> originalUserDefinedOperators; BoundExpression comparisonResult = new BoundTupleOperandPlaceholder(node, type); UnaryOperatorAnalysisResult best = this.UnaryOperatorOverloadResolution(boolOpKind, comparisonResult, node, diagnostics, out resultKind, out originalUserDefinedOperators); if (best.HasValue) { conversionForBoolPlaceholder = new BoundValuePlaceholder(node, type).MakeCompilerGenerated(); conversionForBool = CreateConversion(node, conversionForBoolPlaceholder, best.Conversion, isCast: false, conversionGroupOpt: null, best.Signature.OperandType, diagnostics); boolOperator = best.Signature; return; } // It did not. Give a "not convertible to bool" error. GenerateImplicitConversionError(diagnostics, node, conversion, comparisonResult, boolean); conversionForBoolPlaceholder = null; conversionForBool = null; boolOperator = default; return; }
/// <summary> /// If an element-wise binary operator returns a non-bool type, we will either: /// - prepare a conversion to bool if one exists /// - prepare a truth operator: op_false in the case of an equality (<c>a == b</c> will be lowered to <c>!((a == b).op_false)</c>) or op_true in the case of inequality, /// with the conversion being used for its input. /// </summary> private void PrepareBoolConversionAndTruthOperator(TypeSymbol type, BinaryExpressionSyntax node, BinaryOperatorKind binaryOperator, DiagnosticBag diagnostics, out Conversion conversionForBool, out UnaryOperatorSignature boolOperator) { // Is the operand implicitly convertible to bool? HashSet <DiagnosticInfo> useSiteDiagnostics = null; TypeSymbol boolean = GetSpecialType(SpecialType.System_Boolean, diagnostics, node); Conversion conversion = this.Conversions.ClassifyImplicitConversionFromType(type, boolean, ref useSiteDiagnostics); diagnostics.Add(node, useSiteDiagnostics); if (conversion.IsImplicit) { ReportDiagnosticsIfObsolete(diagnostics, conversion, node, hasBaseReceiver: false); conversionForBool = conversion; boolOperator = default; return; } // It was not. Does it implement operator true (or false)? UnaryOperatorKind boolOpKind; switch (binaryOperator) { case BinaryOperatorKind.Equal: boolOpKind = UnaryOperatorKind.False; break; case BinaryOperatorKind.NotEqual: boolOpKind = UnaryOperatorKind.True; break; default: throw ExceptionUtilities.UnexpectedValue(binaryOperator); } LookupResultKind resultKind; ImmutableArray <MethodSymbol> originalUserDefinedOperators; BoundExpression comparisonResult = new BoundTupleOperandPlaceholder(node, type); UnaryOperatorAnalysisResult best = this.UnaryOperatorOverloadResolution(boolOpKind, comparisonResult, node, diagnostics, out resultKind, out originalUserDefinedOperators); if (best.HasValue) { conversionForBool = best.Conversion; boolOperator = best.Signature; return; } // It did not. Give a "not convertible to bool" error. GenerateImplicitConversionError(diagnostics, node, conversion, comparisonResult, boolean); conversionForBool = Conversion.NoConversion; boolOperator = default; return; }