internal static BoundExpression GiveTupleTypeToDefaultLiteralIfNeeded(BoundExpression expr, TypeSymbol targetType) { if (!expr.IsLiteralDefault() || targetType is null) { return(expr); } Debug.Assert(targetType.StrippedType().IsTupleType); return(new BoundDefaultExpression(expr.Syntax, targetType)); }
private TupleBinaryOperatorInfo.Multiple BindTupleBinaryOperatorNestedInfo(BinaryExpressionSyntax node, BinaryOperatorKind kind, BoundExpression left, BoundExpression right, DiagnosticBag diagnostics) { left = GiveTupleTypeToDefaultLiteralIfNeeded(left, right.Type); right = GiveTupleTypeToDefaultLiteralIfNeeded(right, left.Type); if ((left.Type is null && left.IsLiteralDefault()) || (right.Type is null && right.IsLiteralDefault())) { Error(diagnostics, ErrorCode.ERR_AmbigBinaryOps, node, node.OperatorToken.Text, left.Display, right.Display); 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 leftDefault = left.IsLiteralDefault(); bool rightDefault = right.IsLiteralDefault(); if (leftDefault && rightDefault) { return(false); } return((GetTupleCardinality(left) > 1 || leftDefault) && (GetTupleCardinality(right) > 1 || rightDefault)); }
public static bool IsLiteralNullOrDefault(this BoundExpression node) { return(node.IsLiteralNull() || node.IsLiteralDefault()); }