Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs (C#)

Code before:
                CreateConversion(left.Syntax, operandPlaceholder, implicitConversion, isCast: false, conversionGroupOpt: null, parameterType, diagnostics);
            }

            diagnostics.Add(left.Syntax, useSiteInfo);

            return result;

            bool hasApplicableBooleanOperator(NamedTypeSymbol containingType, string name, TypeSymbol argumentType, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo, out MethodSymbol @operator)
            {
                var operators = ArrayBuilder<MethodSymbol>.GetInstance();
                for (var type = containingType; (object)type != null; type = type.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo))
                {
                    operators.Clear();
                    type.AddOperators(name, operators);

                    for (var i = 0; i < operators.Count; i++)
                    {
                        var op = operators[i];
                        if (op.ParameterCount == 1 && op.DeclaredAccessibility == Accessibility.Public)
                        {
                            var conversion = this.Conversions.ClassifyConversionFromType(argumentType, op.GetParameterType(0), isChecked: CheckOverflowAtRuntime, ref useSiteInfo);
                            if (conversion.IsImplicit)
                            {
                                // Operators defined on interfaces cannot be used with dynamic binding at runtime,
                                // so we don't consider them as applicable.
                                if (op.ContainingType.IsInterface)
                                {
                                    continue;
                                }

                                @operator = op;
                                operators.Free();
                                return true;
                            }
                        }
                    }
                }

                operators.Free();
                @operator = null;
                return false;
            }
        }

        private bool IsValidUserDefinedConditionalLogicalOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorSignature signature,
            BindingDiagnosticBag diagnostics,
            out UnaryOperatorAnalysisResult? trueOperator,
            out UnaryOperatorAnalysisResult? falseOperator)
        {

Review comment (suggestion):
>if (op.ContainingType.IsInterface) [](http://example.com/codeflow?start=32&length=34)

@copilot Please combine interface check with condition in ```if (type.Kind != SymbolKind.NamedType)``` on line 1580 instead. #Closed

Code after:
            }

            var booleanType = Compilation.GetSpecialType(SpecialType.System_Boolean);
            CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
            var implicitConversion = Conversions.ClassifyImplicitConversionFromExpression(left, booleanType, ref useSiteInfo);

            if (implicitConversion.Exists)
            {
                if (left.Type is not null)
                {
                    CreateConversion(left.Syntax, new BoundValuePlaceholder(left.Syntax, left.Type).MakeCompilerGenerated(), implicitConversion, isCast: false, conversionGroupOpt: null, booleanType, diagnostics);
                }
                else
                {
                    Debug.Assert(left.IsLiteralNull());
                }

                diagnostics.Add(left.Syntax, useSiteInfo);
                return true;
            }

            if (type is not NamedTypeSymbol { IsInterface: false } namedType || namedType.IsNullableType())
            {
                diagnostics.Add(left.Syntax, useSiteInfo);
                return false;
            }

            // Strictly speaking, we probably should be digging through nullable type here to look for an operator
            // declared by the underlying type. However, it doesn't look like dynamic binder is able to deal with
            // nullable types while evaluating logical binary operators. Exceptions that it throws look like:
            //
            // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : The type ('S1?') must contain declarations of operator true and operator false
            // Stack Trace:
            //     at CallSite.Target(Closure, CallSite, Object, Object)
            //     at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
            //
            // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : Operator '&&' cannot be applied to operands of type 'S1' and 'S1?'
            // Stack Trace:
            //     at CallSite.Target(Closure, CallSite, Object, Nullable`1)
            //     at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
            var operandPlaceholder = new BoundValuePlaceholder(left.Syntax, namedType).MakeCompilerGenerated();
            UnaryOperatorAnalysisResult result = operatorOverloadResolution(left.Syntax, operandPlaceholder, isNegative ? UnaryOperatorKind.False : UnaryOperatorKind.True, diagnostics);

            if (result.HasValue)
            {
                Debug.Assert(result.Conversion.IsImplicit);
                userDefinedOperator = result.Signature.Method;

                TypeSymbol parameterType = userDefinedOperator.Parameters[0].Type;
                CreateConversion(left.Syntax, operandPlaceholder, result.Conversion, isCast: false, conversionGroupOpt: null, parameterType, diagnostics);
                return true;