Exemple #1
0
        private BinaryOperatorAnalysisResult BinaryOperatorOverloadResolution(BinaryOperatorKind kind, BoundExpression left, BoundExpression right, SyntaxNode node, BindingDiagnosticBag diagnostics)
        {
            var result = BinaryOperatorOverloadResolutionResult.GetInstance();

            this.OverloadResolution.BinaryOperatorOverloadResolution(kind, left, right, result);

            var possiblyBest = result.Best;

            result.Free();
            return(possiblyBest);
        }
        protected override BoundExpression GenerateCall(SyntheticBoundNodeFactory f, BoundExpression receiver, ImmutableArray <BoundExpression> arguments, ImmutableArray <RefKind> refKinds, DiagnosticBag diagnostics)
        {
            // For user-defined operators, the normal shim call approach works
            // fine.  However, we also want to permit shim calls into types
            // with builtin operators, for which we need to do an actual
            // lookup as to which operator we're defining, and a quick
            // jump into part of the operator overload resolution code to see
            // if we're actually in one of those types.
            //
            // This may be incomplete, but is probably(??) sound.
            // TODO(@MattWindsor91): consider refkinds?
            if (ImplementingMethod.OriginalDefinition is SourceUserDefinedOperatorSymbol op)
            {
                Debug.Assert(receiver.Kind == BoundKind.TypeExpression,
                             "receiver of an operator should always be a type");
                var rectype = (BoundTypeExpression)receiver;

                var opdecl = op.GetSyntax();
                Debug.Assert(opdecl != null, "should have operator syntax here");
                var opsyn  = opdecl.OperatorToken;
                var opkind = opsyn.Kind();

                var binder = DeclaringCompilation.GetBinder(ImplementingMethod.GetNonNullSyntaxNode()).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.InShim, this);
                var ovr    = new OverloadResolution(binder);
                var ignore = new HashSet <DiagnosticInfo>();

                if (arguments.Length == 1)
                {
                    (var usuccess, var ukind) = TryGetUnaryOperatorKind(opsyn.Kind());
                    if (usuccess)
                    {
                        var result = UnaryOperatorOverloadResolutionResult.GetInstance();
                        ovr.UnaryOperatorOverloadResolution(ukind, arguments[0], result, ref ignore);
                        if (result.SingleValid())
                        {
                            var bsig = result.Best.Signature;
                            if (bsig.Method == null)
                            {
                                return(f.Unary(bsig.Kind, bsig.ReturnType, arguments[0]));
                            }
                        }
                    }
                }
                else if (arguments.Length == 2)
                {
                    (var bsuccess, var bkind) = TryGetBinaryOperatorKind(opsyn.Kind());
                    if (bsuccess)
                    {
                        var result = BinaryOperatorOverloadResolutionResult.GetInstance();
                        ovr.BinaryOperatorOverloadResolution(bkind, arguments[0], arguments[1], result, ref ignore);
                        if (result.SingleValid())
                        {
                            var bsig = result.Best.Signature;
                            if (bsig.Method == null)
                            {
                                return(f.Binary(bsig.Kind, bsig.ReturnType, arguments[0], arguments[1]));
                            }
                        }
                    }
                }
            }

            return(base.GenerateCall(f, receiver, arguments, refKinds, diagnostics));
        }