/// <summary>
        /// Converts the expression for creating a tuple instance into an expression creating a ValueTuple (if short) or nested ValueTuples (if longer).
        ///
        /// For instance, for a long tuple we'll generate:
        /// creationExpression(ctor=largestCtor, args=firstArgs+(nested creationExpression for remainder, with smaller ctor and next few args))
        /// </summary>
        private BoundNode RewriteTupleCreationExpression(BoundTupleExpression node, ImmutableArray <BoundExpression> rewrittenArguments)
        {
            NamedTypeSymbol underlyingTupleType = node.Type.TupleUnderlyingType;

            ArrayBuilder <NamedTypeSymbol> underlyingTupleTypeChain = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            TupleTypeSymbol.GetUnderlyingTypeChain(underlyingTupleType, underlyingTupleTypeChain);

            try
            {
                // make a creation expression for the smallest type
                NamedTypeSymbol smallestType = underlyingTupleTypeChain.Pop();
                ImmutableArray <BoundExpression> smallestCtorArguments = ImmutableArray.Create(rewrittenArguments,
                                                                                               underlyingTupleTypeChain.Count * (TupleTypeSymbol.RestPosition - 1),
                                                                                               smallestType.Arity);
                var smallestCtor = (MethodSymbol)TupleTypeSymbol.GetWellKnownMemberInType(smallestType.OriginalDefinition,
                                                                                          TupleTypeSymbol.GetTupleCtor(smallestType.Arity),
                                                                                          _diagnostics,
                                                                                          node.Syntax);
                if ((object)smallestCtor == null)
                {
                    return(node);
                }

                MethodSymbol smallestConstructor = smallestCtor.AsMember(smallestType);
                BoundObjectCreationExpression currentCreation = new BoundObjectCreationExpression(node.Syntax, smallestConstructor, smallestCtorArguments);

                if (underlyingTupleTypeChain.Count > 0)
                {
                    NamedTypeSymbol tuple8Type = underlyingTupleTypeChain.Peek();
                    var             tuple8Ctor = (MethodSymbol)TupleTypeSymbol.GetWellKnownMemberInType(tuple8Type.OriginalDefinition,
                                                                                                        TupleTypeSymbol.GetTupleCtor(TupleTypeSymbol.RestPosition),
                                                                                                        _diagnostics,
                                                                                                        node.Syntax);
                    if ((object)tuple8Ctor == null)
                    {
                        return(node);
                    }

                    // make successively larger creation expressions containing the previous one
                    do
                    {
                        ImmutableArray <BoundExpression> ctorArguments = ImmutableArray.Create(rewrittenArguments,
                                                                                               (underlyingTupleTypeChain.Count - 1) * (TupleTypeSymbol.RestPosition - 1),
                                                                                               TupleTypeSymbol.RestPosition - 1)
                                                                         .Add(currentCreation);

                        MethodSymbol constructor = tuple8Ctor.AsMember(underlyingTupleTypeChain.Pop());
                        currentCreation = new BoundObjectCreationExpression(node.Syntax, constructor, ctorArguments);
                    }while (underlyingTupleTypeChain.Count > 0);
                }

                return(currentCreation);
            }
            finally
            {
                underlyingTupleTypeChain.Free();
            }
        }
예제 #2
0
        public static void CheckConstraints(
            this TupleTypeSymbol tuple,
            ConversionsBase conversions,
            SyntaxNode typeSyntax,
            ImmutableArray <Location> elementLocations,
            Compilation currentCompilation,
            DiagnosticBag diagnostics)
        {
            NamedTypeSymbol type = tuple.TupleUnderlyingType;

            if (!RequiresChecking(type))
            {
                return;
            }

            if (typeSyntax.HasErrors)
            {
                return;
            }

            var diagnosticsBuilder = ArrayBuilder <TypeParameterDiagnosticInfo> .GetInstance();

            var underlyingTupleTypeChain = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            TupleTypeSymbol.GetUnderlyingTypeChain(type, underlyingTupleTypeChain);

            int offset = 0;

            foreach (var underlyingTuple in underlyingTupleTypeChain)
            {
                ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder = null;
                CheckTypeConstraints(underlyingTuple, conversions, currentCompilation, diagnosticsBuilder, ref useSiteDiagnosticsBuilder);

                if (useSiteDiagnosticsBuilder != null)
                {
                    diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder);
                }

                foreach (var pair in diagnosticsBuilder)
                {
                    var ordinal = pair.TypeParameter.Ordinal;

                    // If this is the TRest type parameter, we report it on
                    // the entire type syntax as it does not map to any tuple element.
                    var location = ordinal == TupleTypeSymbol.RestIndex ? typeSyntax.Location : elementLocations[ordinal + offset];
                    diagnostics.Add(new CSDiagnostic(pair.DiagnosticInfo, location));
                }

                diagnosticsBuilder.Clear();

                offset += TupleTypeSymbol.RestIndex;
            }

            underlyingTupleTypeChain.Free();
            diagnosticsBuilder.Free();
        }
        private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedTypeSymbol type, ImmutableArray <BoundExpression> rewrittenArguments)
        {
            NamedTypeSymbol underlyingTupleType = type.TupleUnderlyingType ?? type;

            Debug.Assert(underlyingTupleType.IsTupleCompatible());

            ArrayBuilder <NamedTypeSymbol> underlyingTupleTypeChain = ArrayBuilder <NamedTypeSymbol> .GetInstance();

            TupleTypeSymbol.GetUnderlyingTypeChain(underlyingTupleType, underlyingTupleTypeChain);

            try
            {
                // make a creation expression for the smallest type
                NamedTypeSymbol smallestType = underlyingTupleTypeChain.Pop();
                ImmutableArray <BoundExpression> smallestCtorArguments = ImmutableArray.Create(rewrittenArguments,
                                                                                               underlyingTupleTypeChain.Count * (TupleTypeSymbol.RestPosition - 1),
                                                                                               smallestType.Arity);
                var smallestCtor = (MethodSymbol)TupleTypeSymbol.GetWellKnownMemberInType(smallestType.OriginalDefinition,
                                                                                          TupleTypeSymbol.GetTupleCtor(smallestType.Arity),
                                                                                          _diagnostics,
                                                                                          syntax);
                if ((object)smallestCtor == null)
                {
                    return(_factory.BadExpression(type));
                }

                MethodSymbol smallestConstructor = smallestCtor.AsMember(smallestType);
                BoundObjectCreationExpression currentCreation = new BoundObjectCreationExpression(syntax, smallestConstructor, null, smallestCtorArguments);

                if (underlyingTupleTypeChain.Count > 0)
                {
                    NamedTypeSymbol tuple8Type = underlyingTupleTypeChain.Peek();
                    var             tuple8Ctor = (MethodSymbol)TupleTypeSymbol.GetWellKnownMemberInType(tuple8Type.OriginalDefinition,
                                                                                                        TupleTypeSymbol.GetTupleCtor(TupleTypeSymbol.RestPosition),
                                                                                                        _diagnostics,
                                                                                                        syntax);
                    if ((object)tuple8Ctor == null)
                    {
                        return(_factory.BadExpression(type));
                    }

                    // make successively larger creation expressions containing the previous one
                    do
                    {
                        ImmutableArray <BoundExpression> ctorArguments = ImmutableArray.Create(rewrittenArguments,
                                                                                               (underlyingTupleTypeChain.Count - 1) * (TupleTypeSymbol.RestPosition - 1),
                                                                                               TupleTypeSymbol.RestPosition - 1)
                                                                         .Add(currentCreation);

                        MethodSymbol constructor = tuple8Ctor.AsMember(underlyingTupleTypeChain.Pop());
                        currentCreation = new BoundObjectCreationExpression(syntax, constructor, null, ctorArguments);
                    }while (underlyingTupleTypeChain.Count > 0);
                }

                currentCreation = currentCreation.Update(
                    currentCreation.Constructor,
                    currentCreation.Arguments,
                    currentCreation.ArgumentNamesOpt,
                    currentCreation.ArgumentRefKindsOpt,
                    currentCreation.Expanded,
                    currentCreation.ArgsToParamsOpt,
                    currentCreation.ConstantValue,
                    currentCreation.InitializerExpressionOpt,
                    currentCreation.BinderOpt,
                    type);

                return(currentCreation);
            }
            finally
            {
                underlyingTupleTypeChain.Free();
            }
        }