private TupleBinaryOperatorInfo.Multiple BindTupleBinaryOperatorNestedInfo(BinaryExpressionSyntax node, BinaryOperatorKind kind, BoundExpression left, BoundExpression right, BindingDiagnosticBag diagnostics) { left = GiveTupleTypeToDefaultLiteralIfNeeded(left, right.Type); right = GiveTupleTypeToDefaultLiteralIfNeeded(right, left.Type); if (left.IsLiteralDefaultOrImplicitObjectCreation() || right.IsLiteralDefaultOrImplicitObjectCreation()) { ReportBinaryOperatorError(node, diagnostics, node.OperatorToken, left, right, LookupResultKind.Ambiguous); return(TupleBinaryOperatorInfo.Multiple.ErrorInstance); } // Aside from default (which we fixed or ruled out above) and tuple literals, // we must have typed expressions at this point Debug.Assert((object)left.Type != null || left.Kind == BoundKind.TupleLiteral); Debug.Assert((object)right.Type != null || right.Kind == BoundKind.TupleLiteral); int leftCardinality = GetTupleCardinality(left); int rightCardinality = GetTupleCardinality(right); if (leftCardinality != rightCardinality) { Error(diagnostics, ErrorCode.ERR_TupleSizesMismatchForBinOps, node, leftCardinality, rightCardinality); return(TupleBinaryOperatorInfo.Multiple.ErrorInstance); } (ImmutableArray <BoundExpression> leftParts, ImmutableArray <string> leftNames) = GetTupleArgumentsOrPlaceholders(left); (ImmutableArray <BoundExpression> rightParts, ImmutableArray <string> rightNames) = GetTupleArgumentsOrPlaceholders(right); ReportNamesMismatchesIfAny(left, right, leftNames, rightNames, diagnostics); int length = leftParts.Length; Debug.Assert(length == rightParts.Length); var operatorsBuilder = ArrayBuilder <TupleBinaryOperatorInfo> .GetInstance(length); for (int i = 0; i < length; i++) { operatorsBuilder.Add(BindTupleBinaryOperatorInfo(node, kind, leftParts[i], rightParts[i], diagnostics)); } var compilation = this.Compilation; var operators = operatorsBuilder.ToImmutableAndFree(); // typeless tuple literals are not nullable bool leftNullable = left.Type?.IsNullableType() == true; bool rightNullable = right.Type?.IsNullableType() == true; bool isNullable = leftNullable || rightNullable; TypeSymbol leftTupleType = MakeConvertedType(operators.SelectAsArray(o => o.LeftConvertedTypeOpt), node.Left, leftParts, leftNames, isNullable, compilation, diagnostics); TypeSymbol rightTupleType = MakeConvertedType(operators.SelectAsArray(o => o.RightConvertedTypeOpt), node.Right, rightParts, rightNames, isNullable, compilation, diagnostics); return(new TupleBinaryOperatorInfo.Multiple(operators, leftTupleType, rightTupleType)); }
private static bool IsTupleBinaryOperation(BoundExpression left, BoundExpression right) { bool leftDefaultOrNew = left.IsLiteralDefaultOrImplicitObjectCreation(); bool rightDefaultOrNew = right.IsLiteralDefaultOrImplicitObjectCreation(); if (leftDefaultOrNew && rightDefaultOrNew) { return(false); } return((GetTupleCardinality(left) > 1 || leftDefaultOrNew) && (GetTupleCardinality(right) > 1 || rightDefaultOrNew)); }