Пример #1
0
        protected override Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics, bool forCast)
        {
            var arguments = source.Arguments;

            // check if the type is actually compatible type for a tuple of given cardinality
            if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length))
            {
                return(Conversion.NoConversion);
            }

            ImmutableArray <TypeSymbol> targetElementTypes = destination.GetElementTypesOfTupleOrCompatible();

            Debug.Assert(arguments.Length == targetElementTypes.Length);

            // check arguments against flattened list of target element types
            var argumentConversions = ArrayBuilder <Conversion> .GetInstance(arguments.Length);

            for (int i = 0; i < arguments.Length; i++)
            {
                var result = ClassifyConversionFromExpression(arguments[i], targetElementTypes[i], ref useSiteDiagnostics, forCast);
                if (!result.Exists)
                {
                    argumentConversions.Free();
                    return(Conversion.NoConversion);
                }

                argumentConversions.Add(result);
            }

            return(new Conversion(ConversionKind.ExplicitTupleLiteral, argumentConversions.ToImmutableAndFree()));
        }
Пример #2
0
        protected override Conversion GetImplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            var arguments = source.Arguments;

            // check if the type is actually compatible type for a tuple of given cardinality
            if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length))
            {
                return Conversion.NoConversion;
            }

            ImmutableArray<TypeSymbol> targetElementTypes = destination.GetElementTypesOfTupleOrCompatible();
            Debug.Assert(arguments.Length == targetElementTypes.Length);

            // check arguments against flattened list of target element types 
            var argumentConversions = ArrayBuilder<Conversion>.GetInstance(arguments.Length);
            for (int i = 0; i < arguments.Length; i++)
            {
                var argument = arguments[i];
                var result = ClassifyImplicitConversionFromExpression(argument, targetElementTypes[i], ref useSiteDiagnostics);
                if (!result.Exists)
                {
                    argumentConversions.Free();
                    return Conversion.NoConversion;
                }

                argumentConversions.Add(result);
            }

            return new Conversion(ConversionKind.ImplicitTupleLiteral, argumentConversions.ToImmutableAndFree());
        }
Пример #3
0
        public override BoundNode VisitTupleLiteral(BoundTupleLiteral node)
        {
            if (_inExpressionLambda)
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsTupleLiteral, node);
            }

            return(base.VisitTupleLiteral(node));
        }
Пример #4
0
        private void CheckForDeconstructionAssignmentToSelf(BoundTupleLiteral leftTuple, BoundExpression right)
        {
            while (right.Kind == BoundKind.Conversion)
            {
                var conversion = (BoundConversion)right;
                switch (conversion.ConversionKind)
                {
                case ConversionKind.Deconstruction:
                case ConversionKind.ImplicitTupleLiteral:
                case ConversionKind.Identity:
                    right = conversion.Operand;
                    break;

                default:
                    return;
                }
            }

            if (right.Kind != BoundKind.ConvertedTupleLiteral && right.Kind != BoundKind.TupleLiteral)
            {
                return;
            }

            var rightTuple    = (BoundTupleExpression)right;
            var leftArguments = leftTuple.Arguments;
            int length        = leftArguments.Length;

            Debug.Assert(length == rightTuple.Arguments.Length);

            for (int i = 0; i < length; i++)
            {
                var leftArgument  = leftArguments[i];
                var rightArgument = rightTuple.Arguments[i];

                if (leftArgument.Kind == BoundKind.TupleLiteral)
                {
                    CheckForDeconstructionAssignmentToSelf((BoundTupleLiteral)leftArgument, rightArgument);
                }
                else if (IsSameLocalOrField(leftArgument, rightArgument))
                {
                    Error(ErrorCode.WRN_AssignmentToSelf, leftArgument);
                }
            }
        }
Пример #5
0
        private BoundDeconstructionConstructionStep MakeDeconstructionConstructionStep(CSharpSyntaxNode node, DiagnosticBag diagnostics,
                                                                                       ImmutableArray <BoundDeconstructValuePlaceholder> constructionInputs)
        {
            var tuple = TupleTypeSymbol.Create(locationOpt: null,
                                               elementTypes: constructionInputs.SelectAsArray(e => e.Type),
                                               elementLocations: default(ImmutableArray <Location>),
                                               elementNames: default(ImmutableArray <string>),
                                               compilation: Compilation,
                                               diagnostics: diagnostics,
                                               syntax: node);

            var outputPlaceholder = new BoundDeconstructValuePlaceholder(node, tuple)
            {
                WasCompilerGenerated = true
            };

            BoundExpression construction = new BoundTupleLiteral(node, default(ImmutableArray <string>), constructionInputs.CastArray <BoundExpression>(), tuple);

            return(new BoundDeconstructionConstructionStep(node, construction, outputPlaceholder));
        }
Пример #6
0
        /// <summary>
        /// For cases where the RHS of a deconstruction-declaration is a tuple literal, we merge type information from both the LHS and RHS.
        /// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type.
        /// Returns null if a merged tuple type could not be fabricated.
        /// </summary>
        private static TypeSymbol MakeMergedTupleType(ArrayBuilder <DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            int leftLength  = lhsVariables.Count;
            int rightLength = rhsLiteral.Arguments.Length;

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(leftLength);

            for (int i = 0; i < rightLength; i++)
            {
                BoundExpression element    = rhsLiteral.Arguments[i];
                TypeSymbol      mergedType = element.Type;

                if (i < leftLength)
                {
                    var variable = lhsVariables[i];
                    if (variable.HasNestedVariables)
                    {
                        if (element.Kind == BoundKind.TupleLiteral)
                        {
                            // (variables) on the left and (elements) on the right
                            mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics);
                        }
                        else if ((object)mergedType == null)
                        {
                            // (variables) on the left and null on the right
                            Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                        }
                    }
                    else
                    {
                        if ((object)variable.Single.Type != null)
                        {
                            // typed-variable on the left
                            mergedType = variable.Single.Type;
                        }
                        else if ((object)mergedType == null)
                        {
                            // typeless-variable on the left and typeless-element on the right
                            Error(diagnostics, ErrorCode.ERR_DeconstructCouldNotInferMergedType, syntax, variable.Syntax, element.Syntax);
                        }
                    }
                }
                else
                {
                    if ((object)mergedType == null)
                    {
                        // a typeless element on the right, matching no variable on the left
                        Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                    }
                }

                typesBuilder.Add(mergedType);
            }

            if (typesBuilder.Any(t => t == null))
            {
                typesBuilder.Free();
                return(null);
            }

            return(TupleTypeSymbol.Create(locationOpt: null, elementTypes: typesBuilder.ToImmutableAndFree(), elementLocations: default(ImmutableArray <Location>), elementNames: default(ImmutableArray <string>), compilation: compilation, diagnostics: diagnostics));
        }
 public override BoundNode VisitTupleLiteral(BoundTupleLiteral node)
 {
     return(VisitTupleExpression(node));
 }
Пример #8
0
 protected override Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics, bool forCast)
 {
     // Tuple conversions require a Binder, recursively
     throw ExceptionUtilities.Unreachable;
 }
Пример #9
0
 protected override Conversion GetExplicitTupleLiteralConversion(BoundTupleLiteral source, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics, bool forCast)
 {
     // Tuple conversions require a Binder, recursively
     throw ExceptionUtilities.Unreachable;
 }
 public override BoundNode VisitTupleLiteral(BoundTupleLiteral node)
 {
     return VisitTupleExpression(node);
 }
Пример #11
0
        private void MakeExplicitParameterTypeInferences(Binder binder, BoundTupleLiteral argument, TypeSymbol target, bool isExactInference, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // if tuple has a type we will try to match the type as a single input
            // Example:
            //      if   "(a: 1, b: 2)" is passed as   T arg
            //      then T becomes (int a, int b)
            var source = argument.Type;
            if (IsReallyAType(source))
            {
                if (isExactInference)
                {
                    // SPEC: * If V is one of the unfixed Xi then U is added to the set of
                    // SPEC:   exact bounds for Xi.
                    if (ExactTypeParameterInference(source, target))
                    {
                        return;
                    }
                }
                else
                {
                    // SPEC: A lower-bound inference from a type U to a type V is made as follows:

                    // SPEC: * If V is one of the unfixed Xi then U is added to the set of 
                    // SPEC:   lower bounds for Xi.

                    if (LowerBoundTypeParameterInference(source, target))
                    {
                        return;
                    }
                }
            }

            // try match up element-wise to the destination tuple (or underlying type)
            // Example:
            //      if   "(a: 1, b: "qq")" is passed as   (T, U) arg
            //      then T becomes int and U becomes string
            if (target.Kind != SymbolKind.NamedType)
            {
                // tuples can only match to tuples or tuple underlying types.
                return;
            }

            var destination = (NamedTypeSymbol)target;
            var sourceArguments = argument.Arguments;

            // check if the type is actually compatible type for a tuple of given cardinality
            if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(sourceArguments.Length))
            {
                // target is not a tuple of appropriate shape
                return;
            }

            var destTypes = destination.GetElementTypesOfTupleOrCompatible();
            Debug.Assert(sourceArguments.Length == destTypes.Length);

            // NOTE: we are losing tuple element names when recursing into argument expressions.
            //       that is ok, because we are inferring type parameters used in the matching elements, 
            //       This is not the situation where entire tuple literal is used to infer a single type param

            for (int i = 0; i < sourceArguments.Length; i++)
            {
                var sourceArgument = sourceArguments[i];
                var destType = destTypes[i];
                MakeExplicitParameterTypeInferences(binder, sourceArgument, destType, isExactInference, ref useSiteDiagnostics);
            }
        }
Пример #12
0
        private BoundExpression CreateTupleLiteralConversion(CSharpSyntaxNode syntax, BoundTupleLiteral sourceTuple, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
        {
            // We have a successful tuple conversion; rather than producing a separate conversion node 
            // which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments.

            Debug.Assert(conversion.Kind == ConversionKind.ImplicitTupleLiteral || conversion.Kind == ConversionKind.ImplicitNullable);
            Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType());

            TypeSymbol destinationWithoutNullable = conversion.Kind == ConversionKind.ImplicitNullable ?
                                                                           destinationWithoutNullable = destination.GetNullableUnderlyingType() :
                                                                           destination;

            NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable;

            if (targetType.IsTupleType)
            {
                var destTupleType = (TupleTypeSymbol)targetType;
                // do not lose the original element names in the literal if different from names in the target

                // Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013)
                targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt);
            }

            var arguments = sourceTuple.Arguments;
            var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length);

            ImmutableArray<TypeSymbol> targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible();
            Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?");

            for (int i = 0; i < arguments.Length; i++)
            {
                var argument = arguments[i];
                var destType = targetElementTypes[i];

                HashSet<DiagnosticInfo> useSiteDiagnostics = null;
                Conversion elementConversion;
                if (isCast)
                {
                    elementConversion = this.Conversions.ClassifyConversionForCast(argument, destType, ref useSiteDiagnostics);
                }
                else
                {
                    elementConversion = this.Conversions.ClassifyConversionFromExpression(argument, destType, ref useSiteDiagnostics);
                }

                diagnostics.Add(syntax, useSiteDiagnostics);
                convertedArguments.Add(CreateConversion(argument.Syntax, argument, elementConversion, isCast, destType, diagnostics));
            }

            BoundExpression result = new BoundConvertedTupleLiteral(
                sourceTuple.Syntax,
                sourceTuple.Type,
                convertedArguments.ToImmutableAndFree(), 
                targetType);

            // We need to preserve any conversion that changes the type (even identity conversions),
            // or that was explicitly written in code (so that GetSemanticInfo can find the syntax in the bound tree).
            if (!isCast && targetType == destination)
            {
                return result;
            }

            // if we have a nullable cast combined with a name/dynamic cast
            // name/dynamic cast must happen before converting to nullable
            if (conversion.Kind == ConversionKind.ImplicitNullable &&
                destinationWithoutNullable != targetType)
            {
                Debug.Assert(destinationWithoutNullable.Equals(targetType, ignoreDynamic: true));

                result = new BoundConversion(
                    syntax,
                    result,
                    Conversion.Identity,
                    @checked: false,
                    explicitCastInCode: isCast,
                    constantValueOpt: ConstantValue.NotAvailable,
                    type: destinationWithoutNullable)
                { WasCompilerGenerated = sourceTuple.WasCompilerGenerated };
            }
                                  
            return new BoundConversion(
                syntax,
                result,
                conversion,
                @checked: false,
                explicitCastInCode: isCast,
                constantValueOpt: ConstantValue.NotAvailable,
                type: destination)
            { WasCompilerGenerated = sourceTuple.WasCompilerGenerated };
        }
Пример #13
0
        private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTupleLiteral sourceTuple, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
        {
            // We have a successful tuple conversion; rather than producing a separate conversion node 
            // which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments.
            Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType());

            var destinationWithoutNullable = destination;
            var conversionWithoutNullable = conversion;

            if (conversion.Kind == ConversionKind.ImplicitNullable)
            {
                destinationWithoutNullable = destination.GetNullableUnderlyingType();
                conversionWithoutNullable = conversion.UnderlyingConversions[0];
            }

            Debug.Assert(conversionWithoutNullable.IsTupleLiteralConversion);

            NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable;
            if (targetType.IsTupleType)
            {
                var destTupleType = (TupleTypeSymbol)targetType;
                // do not lose the original element names in the literal if different from names in the target

                TupleTypeSymbol.ReportNamesMismatchesIfAny(targetType, sourceTuple, diagnostics);

                // Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013)
                targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt);
            }

            var arguments = sourceTuple.Arguments;
            var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length);

            ImmutableArray<TypeSymbol> targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible();
            Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?");
            var underlyingConversions = conversionWithoutNullable.UnderlyingConversions;

            for (int i = 0; i < arguments.Length; i++)
            {
                var argument = arguments[i];
                var destType = targetElementTypes[i];
                var elementConversion = underlyingConversions[i];

                convertedArguments.Add(CreateConversion(argument.Syntax, argument, elementConversion, isCast, destType, diagnostics));
            }

            BoundExpression result = new BoundConvertedTupleLiteral(
                sourceTuple.Syntax,
                sourceTuple.Type,
                convertedArguments.ToImmutableAndFree(),
                targetType);

            if (sourceTuple.Type != destination)
            {
                // literal cast is applied to the literal 
                result = new BoundConversion(
                    sourceTuple.Syntax,
                    result,
                    conversion,
                    @checked: false,
                    explicitCastInCode: isCast,
                    constantValueOpt: ConstantValue.NotAvailable,
                    type: destination);
            }

            // If we had a cast in the code, keep conversion in the tree.
            // even though the literal is already converted to the target type.
            if (isCast)
            {
                result = new BoundConversion(
                    syntax,
                    result,
                    Conversion.Identity,
                    @checked: false,
                    explicitCastInCode: isCast,
                    constantValueOpt: ConstantValue.NotAvailable,
                    type: destination);
            }

            return result;
        }
Пример #14
0
        private BoundDeconstructionConstructionStep MakeDeconstructionConstructionStep(CSharpSyntaxNode node, DiagnosticBag diagnostics,
                                                        ImmutableArray<BoundDeconstructValuePlaceholder> constructionInputs)
        {
            var tuple = TupleTypeSymbol.Create(locationOpt: null,
                           elementTypes: constructionInputs.SelectAsArray(e => e.Type),
                           elementLocations: default(ImmutableArray<Location>),
                           elementNames: default(ImmutableArray<string>),
                           compilation: Compilation,
                           diagnostics: diagnostics,
                           syntax: node);

            var outputPlaceholder = new BoundDeconstructValuePlaceholder(node, tuple) { WasCompilerGenerated = true };

            BoundExpression construction = new BoundTupleLiteral(node, default(ImmutableArray<string>), constructionInputs.CastArray<BoundExpression>(), tuple);
            return new BoundDeconstructionConstructionStep(node, construction, outputPlaceholder);
        }
Пример #15
0
        private void MakeOutputTypeInferences(Binder binder, BoundTupleLiteral argument, TypeSymbol formalType, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            if (formalType.Kind != SymbolKind.NamedType)
            {
                // tuples can only match to tuples or tuple underlying types.
                return;
            }

            var destination = (NamedTypeSymbol)formalType;

            Debug.Assert(argument.Type == null, "should not need to dig into elements if tuple has natural type");
            var sourceArguments = argument.Arguments;

            // check if the type is actually compatible type for a tuple of given cardinality
            if (!destination.IsTupleOrCompatibleWithTupleOfCardinality(sourceArguments.Length))
            {
                return;
            }

            var destTypes = destination.GetElementTypesOfTupleOrCompatible();
            Debug.Assert(sourceArguments.Length == destTypes.Length);

            for (int i = 0; i < sourceArguments.Length; i++)
            {
                var sourceArgument = sourceArguments[i];
                var destType = destTypes[i];
                MakeOutputTypeInferences(binder, sourceArgument, destType, ref useSiteDiagnostics);
            }
        }
Пример #16
0
        /// <summary>
        /// For cases where the RHS of a deconstruction-declaration is a tuple literal, we merge type information from both the LHS and RHS.
        /// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type.
        /// Returns null if a merged tuple type could not be fabricated.
        /// </summary>
        private static TypeSymbol MakeMergedTupleType(ArrayBuilder<DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            int leftLength = lhsVariables.Count;
            int rightLength = rhsLiteral.Arguments.Length;

            var typesBuilder = ArrayBuilder<TypeSymbol>.GetInstance(leftLength);
            for (int i = 0; i < rightLength; i++)
            {
                BoundExpression element = rhsLiteral.Arguments[i];
                TypeSymbol mergedType = element.Type;

                if (i < leftLength)
                {
                    var variable = lhsVariables[i];
                    if (variable.HasNestedVariables)
                    {
                        if (element.Kind == BoundKind.TupleLiteral)
                        {
                            // (variables) on the left and (elements) on the right
                            mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics);
                        }
                        else if ((object)mergedType == null)
                        {
                            // (variables) on the left and null on the right
                            Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                        }
                    }
                    else
                    {
                        if ((object)variable.Single.Type != null)
                        {
                            // typed-variable on the left
                            mergedType = variable.Single.Type;
                        }
                    }
                }
                else
                {
                    if ((object)mergedType == null)
                    {
                        // a typeless element on the right, matching no variable on the left
                        Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                    }
                }

                typesBuilder.Add(mergedType);
            }

            if (typesBuilder.Any(t => t == null))
            {
                typesBuilder.Free();
                return null;
            }

            return TupleTypeSymbol.Create(locationOpt: null, elementTypes: typesBuilder.ToImmutableAndFree(), elementLocations: default(ImmutableArray<Location>),
                                    elementNames: default(ImmutableArray<string>), compilation: compilation, diagnostics: diagnostics);
        }
Пример #17
0
 public override BoundNode VisitTupleLiteral(BoundTupleLiteral node)
 {
     throw ExceptionUtilities.Unreachable;
 }
Пример #18
0
        /// <summary>
        /// For cases where the RHS of a deconstruction-declaration is a tuple literal, we merge type information from both the LHS and RHS.
        /// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type.
        /// Returns null if a merged tuple type could not be fabricated.
        /// </summary>
        private static TypeSymbol MakeMergedTupleType(ArrayBuilder <DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
        {
            int leftLength  = lhsVariables.Count;
            int rightLength = rhsLiteral.Arguments.Length;

            var typesBuilder = ArrayBuilder <TypeSymbol> .GetInstance(leftLength);

            var locationsBuilder = ArrayBuilder <Location> .GetInstance(leftLength);

            for (int i = 0; i < rightLength; i++)
            {
                BoundExpression element    = rhsLiteral.Arguments[i];
                TypeSymbol      mergedType = element.Type;

                if (i < leftLength)
                {
                    var variable = lhsVariables[i];
                    if (variable.HasNestedVariables)
                    {
                        if (element.Kind == BoundKind.TupleLiteral)
                        {
                            // (variables) on the left and (elements) on the right
                            mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics);
                        }
                        else if ((object)mergedType == null)
                        {
                            // (variables) on the left and null on the right
                            Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                        }
                    }
                    else
                    {
                        if ((object)variable.Single.Type != null)
                        {
                            // typed-variable on the left
                            mergedType = variable.Single.Type;
                        }
                    }
                }
                else
                {
                    if ((object)mergedType == null)
                    {
                        // a typeless element on the right, matching no variable on the left
                        Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax);
                    }
                }

                typesBuilder.Add(mergedType);
                locationsBuilder.Add(element.Syntax.Location);
            }

            if (typesBuilder.Any(t => t == null))
            {
                typesBuilder.Free();
                locationsBuilder.Free();
                return(null);
            }

            // The tuple created here is not identical to the one created by
            // DeconstructionVariablesAsTuple. It represents a smaller
            // tree of types used for figuring out natural types in tuple literal.
            return(TupleTypeSymbol.Create(
                       locationOpt: null,
                       elementTypes: typesBuilder.ToImmutableAndFree(),
                       elementLocations: locationsBuilder.ToImmutableAndFree(),
                       elementNames: default(ImmutableArray <string>),
                       compilation: compilation,
                       diagnostics: diagnostics,
                       shouldCheckConstraints: true,
                       errorPositions: default(ImmutableArray <bool>),
                       syntax: syntax));
        }
        public override BoundNode VisitTupleLiteral(BoundTupleLiteral node)
        {
            if (_inExpressionLambda)
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsTupleLiteral, node);
            }

            return base.VisitTupleLiteral(node);
        }