private TupleBinaryOperatorInfo BindTupleDynamicBinaryOperatorSingleInfo(
            BinaryExpressionSyntax node,
            BinaryOperatorKind kind,
            BoundExpression left,
            BoundExpression right,
            BindingDiagnosticBag diagnostics
            )
        {
            // This method binds binary == and != operators where one or both of the operands are dynamic.
            Debug.Assert(
                (object)left.Type != null && left.Type.IsDynamic() ||
                (object)right.Type != null && right.Type.IsDynamic()
                );

            bool hasError = false;

            if (!IsLegalDynamicOperand(left) || !IsLegalDynamicOperand(right))
            {
                // Operator '{0}' cannot be applied to operands of type '{1}' and '{2}'
                Error(
                    diagnostics,
                    ErrorCode.ERR_BadBinaryOps,
                    node,
                    node.OperatorToken.Text,
                    left.Display,
                    right.Display
                    );
                hasError = true;
            }

            BinaryOperatorKind elementOperatorKind = hasError
                ? kind
                : kind.WithType(BinaryOperatorKind.Dynamic);
            TypeSymbol dynamicType = hasError ? CreateErrorType() : Compilation.DynamicType;

            // We'll want to dynamically invoke operators op_true (/op_false) for equality (/inequality) comparison, but we don't need
            // to prepare either a conversion or a truth operator. Those can just be synthesized during lowering.
            return(new TupleBinaryOperatorInfo.Single(
                       dynamicType,
                       dynamicType,
                       elementOperatorKind,
                       methodSymbolOpt: null,
                       conversionForBool: Conversion.Identity,
                       boolOperator: default
                       ));
        }
Exemple #2
0
        private BoundExpression BindDynamicBinaryOperator(
            BinaryExpressionSyntax node,
            BinaryOperatorKind kind,
            BoundExpression left,
            BoundExpression right,
            DiagnosticBag diagnostics)
        {
            // This method binds binary * / % + - << >> < > <= >= == != & ! ^ && || operators where one or both
            // of the operands are dynamic.
            Debug.Assert((object)left.Type != null && left.Type.IsDynamic() || (object)right.Type != null && right.Type.IsDynamic());

            bool hasError = false;
            bool leftValidOperand = IsLegalDynamicOperand(left);
            bool rightValidOperand = IsLegalDynamicOperand(right);

            if (!leftValidOperand || !rightValidOperand)
            {
                // Operator '{0}' cannot be applied to operands of type '{1}' and '{2}'
                Error(diagnostics, ErrorCode.ERR_BadBinaryOps, node, node.OperatorToken.Text, left.Display, right.Display);
                hasError = true;
            }

            MethodSymbol userDefinedOperator = null;

            if (kind.IsLogical() && leftValidOperand)
            {
                // We need to make sure left is either implicitly convertible to Boolean or has user defined truth operator.
                //   left && right is lowered to {op_False|op_Implicit}(left) ? left : And(left, right) 
                //   left || right is lowered to {op_True|!op_Implicit}(left) ? left : Or(left, right)
                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                if (!IsValidDynamicCondition(left, isNegative: kind == BinaryOperatorKind.LogicalAnd, useSiteDiagnostics: ref useSiteDiagnostics, userDefinedOperator: out userDefinedOperator))
                {
                    // Dev11 reports ERR_MustHaveOpTF. The error was shared between this case and user-defined binary Boolean operators.
                    // We report two distinct more specific error messages.
                    Error(diagnostics, ErrorCode.ERR_InvalidDynamicCondition, node.Left, left.Type, kind == BinaryOperatorKind.LogicalAnd ? "false" : "true");

                    hasError = true;
                }
                diagnostics.Add(node, useSiteDiagnostics);
            }

            return new BoundBinaryOperator(
                syntax: node,
                operatorKind: (hasError ? kind : kind.WithType(BinaryOperatorKind.Dynamic)).WithOverflowChecksIfApplicable(CheckOverflowAtRuntime),
                left: left,
                right: right,
                constantValueOpt: ConstantValue.NotAvailable,
                methodOpt: userDefinedOperator,
                resultKind: LookupResultKind.Viable,
                type: Compilation.DynamicType,
                hasErrors: hasError);
        }