/// <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(); } }
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(); } }