private BoundExpression RewriteTupleConversion( CSharpSyntaxNode syntax, BoundExpression rewrittenOperand, ConversionKind conversionKind, bool @checked, bool explicitCastInCode, NamedTypeSymbol rewrittenType) { var destElementTypes = rewrittenType.GetElementTypesOfTupleOrCompatible(); var numElements = destElementTypes.Length; ImmutableArray<FieldSymbol> srcElementFields; TypeSymbol srcType = rewrittenOperand.Type; if (srcType.IsTupleType) { srcElementFields = ((TupleTypeSymbol)srcType).TupleElementFields; } else { // The following codepath should be very uncommon (if reachable at all) // we should generally not see tuple compatible types in bound trees and // see actual tuple types instead. Debug.Assert(srcType.IsTupleCompatible()); // PERF: if allocations here become nuisance, consider caching the TupleTypeSymbol // in the type symbols that can actually be tuple compatible srcElementFields = TupleTypeSymbol.Create((NamedTypeSymbol)srcType).TupleElementFields; } var fieldAccessorsBuilder = ArrayBuilder<BoundExpression>.GetInstance(numElements); BoundAssignmentOperator assignmentToTemp; var savedTuple = _factory.StoreToTemp(rewrittenOperand, out assignmentToTemp); for (int i = 0; i < numElements; i++) { var field = srcElementFields[i]; DiagnosticInfo useSiteInfo = field.GetUseSiteDiagnostic(); if ((object)useSiteInfo != null && useSiteInfo.Severity == DiagnosticSeverity.Error) { Symbol.ReportUseSiteDiagnostic(useSiteInfo, _diagnostics, syntax.Location); } var fieldAccess = MakeTupleFieldAccess(syntax, field, savedTuple, null, LookupResultKind.Empty); var convertedFieldAccess = MakeConversion(fieldAccess, destElementTypes[i], @checked); fieldAccessorsBuilder.Add(convertedFieldAccess); } var result = MakeTupleCreationExpression(syntax, rewrittenType, fieldAccessorsBuilder.ToImmutableAndFree()); return _factory.Sequence(savedTuple.LocalSymbol, assignmentToTemp, result); }