| File: Lowering\LocalRewriter\LocalRewriter_TupleCreationExpression.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; using System.Collections.Immutable; using System.Diagnostics; namespace Microsoft.CodeAnalysis.CSharp { internal partial class LocalRewriter { public override BoundNode VisitTupleLiteral(BoundTupleLiteral node) { throw ExceptionUtilities.Unreachable(); } public override BoundNode VisitConvertedTupleLiteral(BoundConvertedTupleLiteral node) { return VisitTupleExpression(node); } private BoundNode VisitTupleExpression(BoundTupleExpression node) { ImmutableArray<BoundExpression> rewrittenArguments = VisitList(node.Arguments); return RewriteTupleCreationExpression(node, rewrittenArguments); } /// <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 BoundExpression RewriteTupleCreationExpression(BoundTupleExpression node, ImmutableArray<BoundExpression> rewrittenArguments) { Debug.Assert(node.Type is { }); return MakeTupleCreationExpression(node.Syntax, (NamedTypeSymbol)node.Type, rewrittenArguments); } private BoundExpression MakeTupleCreationExpression(SyntaxNode syntax, NamedTypeSymbol type, ImmutableArray<BoundExpression> rewrittenArguments) { Debug.Assert(type.IsTupleType); ArrayBuilder<NamedTypeSymbol> underlyingTupleTypeChain = ArrayBuilder<NamedTypeSymbol>.GetInstance(); NamedTypeSymbol.GetUnderlyingTypeChain(type, underlyingTupleTypeChain); try { // make a creation expression for the smallest type NamedTypeSymbol smallestType = underlyingTupleTypeChain.Pop(); ImmutableArray<BoundExpression> smallestCtorArguments = ImmutableArray.Create(rewrittenArguments, underlyingTupleTypeChain.Count * (NamedTypeSymbol.ValueTupleRestPosition - 1), smallestType.Arity); var smallestCtor = (MethodSymbol?)NamedTypeSymbol.GetWellKnownMemberInType(smallestType.OriginalDefinition, NamedTypeSymbol.GetTupleCtor(smallestType.Arity), _diagnostics, syntax); if (smallestCtor is null) { return _factory.BadExpression(type); } MethodSymbol smallestConstructor = smallestCtor.AsMember(smallestType); BoundObjectCreationExpression currentCreation = new BoundObjectCreationExpression(syntax, smallestConstructor, smallestCtorArguments); Binder.CheckRequiredMembersInObjectInitializer(smallestConstructor, initializers: ImmutableArray<BoundExpression>.Empty, syntax, _diagnostics); if (underlyingTupleTypeChain.Count > 0) { NamedTypeSymbol tuple8Type = underlyingTupleTypeChain.Peek(); var tuple8Ctor = (MethodSymbol?)NamedTypeSymbol.GetWellKnownMemberInType(tuple8Type.OriginalDefinition, NamedTypeSymbol.GetTupleCtor(NamedTypeSymbol.ValueTupleRestPosition), _diagnostics, syntax); if (tuple8Ctor is null) { return _factory.BadExpression(type); } Binder.CheckRequiredMembersInObjectInitializer(tuple8Ctor, initializers: ImmutableArray<BoundExpression>.Empty, syntax, _diagnostics); // make successively larger creation expressions containing the previous one do { ImmutableArray<BoundExpression> ctorArguments = ImmutableArray.Create(rewrittenArguments, (underlyingTupleTypeChain.Count - 1) * (NamedTypeSymbol.ValueTupleRestPosition - 1), NamedTypeSymbol.ValueTupleRestPosition - 1) .Add(currentCreation); MethodSymbol constructor = tuple8Ctor.AsMember(underlyingTupleTypeChain.Pop()); currentCreation = new BoundObjectCreationExpression(syntax, constructor, ctorArguments); } while (underlyingTupleTypeChain.Count > 0); } currentCreation = currentCreation.Update( currentCreation.Constructor, currentCreation.Arguments, currentCreation.ArgumentNamesOpt, currentCreation.ArgumentRefKindsOpt, currentCreation.Expanded, currentCreation.ArgsToParamsOpt, currentCreation.DefaultArguments, currentCreation.ConstantValueOpt, currentCreation.InitializerExpressionOpt, type); return currentCreation; } finally { underlyingTupleTypeChain.Free(); } } } }