private void AccessTupleFields(BoundDeconstructionAssignmentOperator node, BoundDeconstructionDeconstructStep deconstruction, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders) { var target = PlaceholderReplacement(deconstruction.TargetPlaceholder); var tupleType = target.Type.IsTupleType ? target.Type : TupleTypeSymbol.Create((NamedTypeSymbol)target.Type); var tupleElementTypes = tupleType.TupleElementTypes; var numElements = tupleElementTypes.Length; CSharpSyntaxNode syntax = node.Syntax; // save the target as we need to access it multiple times BoundAssignmentOperator assignmentToTemp; var savedTuple = _factory.StoreToTemp(target, out assignmentToTemp); stores.Add(assignmentToTemp); temps.Add(savedTuple.LocalSymbol); // list the tuple fields accessors var fields = tupleType.TupleElementFields; for (int i = 0; i < numElements; i++) { var field = fields[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); AddPlaceholderReplacement(deconstruction.OutputPlaceholders[i], fieldAccess); placeholders.Add(deconstruction.OutputPlaceholders[i]); } }
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) { var temps = ArrayBuilder<LocalSymbol>.GetInstance(); var stores = ArrayBuilder<BoundExpression>.GetInstance(); var placeholders = ArrayBuilder<BoundValuePlaceholderBase>.GetInstance(); // evaluate left-hand-side side-effects ImmutableArray<BoundExpression> lhsTargets = LeftHandSideSideEffects(node.LeftVariables, temps, stores); // get or make right-hand-side values BoundExpression loweredRight = VisitExpression(node.Right); ApplyDeconstructions(node, temps, stores, placeholders, loweredRight); ApplyConversions(node, temps, stores, placeholders); ApplyAssignments(node, stores, lhsTargets); BoundExpression returnValue = MakeReturnValue(node, placeholders); BoundExpression result = _factory.Sequence(temps.ToImmutable(), stores.ToImmutable(), returnValue); RemovePlaceholderReplacements(placeholders); placeholders.Free(); temps.Free(); stores.Free(); return result; }
/// <summary> /// Applies the conversions. /// Adds any new locals to the temps and any new expressions to be evaluated to the stores. /// </summary> private void ApplyConversions(BoundDeconstructionAssignmentOperator node, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders) { int numConversions = node.ConversionSteps.Length; var conversionLocals = ArrayBuilder<BoundExpression>.GetInstance(); foreach (var conversionInfo in node.ConversionSteps) { // lower the conversions and assignments to locals var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, conversionInfo.OutputPlaceholder.Type, SynthesizedLocalKind.LoweringTemp); var localBound = new BoundLocal(node.Syntax, localSymbol, null, conversionInfo.OutputPlaceholder.Type) { WasCompilerGenerated = true }; temps.Add(localSymbol); conversionLocals.Add(localBound); AddPlaceholderReplacement(conversionInfo.OutputPlaceholder, localBound); placeholders.Add(conversionInfo.OutputPlaceholder); var conversion = VisitExpression(conversionInfo.Assignment); stores.Add(conversion); } }
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) { Debug.Assert(node.DeconstructSteps != null); Debug.Assert(node.AssignmentSteps != null); var temps = ArrayBuilder<LocalSymbol>.GetInstance(); var stores = ArrayBuilder<BoundExpression>.GetInstance(); var placeholders = ArrayBuilder<BoundValuePlaceholderBase>.GetInstance(); // evaluate left-hand-side side-effects var lhsTargets = LeftHandSideSideEffects(node.LeftVariables, temps, stores); // get or make right-hand-side values BoundExpression loweredRight = VisitExpression(node.Right); AddPlaceholderReplacement(node.DeconstructSteps[0].TargetPlaceholder, loweredRight); placeholders.Add(node.DeconstructSteps[0].TargetPlaceholder); foreach (var deconstruction in node.DeconstructSteps) { if (deconstruction.DeconstructInvocationOpt == null) { // tuple case AccessTupleFields(node, deconstruction, temps, stores, placeholders); } else { CallDeconstruct(node, deconstruction, temps, stores, placeholders); } } int numAssignments = node.AssignmentSteps.Length; for (int i = 0; i < numAssignments; i++) { // lower the assignment and replace the placeholders for its outputs in the process var assignmentInfo = node.AssignmentSteps[i]; AddPlaceholderReplacement(assignmentInfo.OutputPlaceholder, lhsTargets[i]); var assignment = VisitExpression(assignmentInfo.Assignment); RemovePlaceholderReplacement(assignmentInfo.OutputPlaceholder); stores.Add(assignment); } var result = _factory.Sequence(temps.ToImmutable(), stores.ToImmutable(), new BoundVoid(node.Syntax, node.Type)); RemovePlaceholderReplacements(placeholders); placeholders.Free(); temps.Free(); stores.Free(); return result; }
/// <summary> /// Applies the deconstructions. /// Adds any new locals to the temps and any new expressions to be evaluated to the stores. /// </summary> private void ApplyDeconstructions(BoundDeconstructionAssignmentOperator node, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders, BoundExpression loweredRight) { var firstDeconstructStep = node.DeconstructSteps[0]; AddPlaceholderReplacement(firstDeconstructStep.InputPlaceholder, loweredRight); placeholders.Add(firstDeconstructStep.InputPlaceholder); foreach (BoundDeconstructionDeconstructStep deconstruction in node.DeconstructSteps) { if (deconstruction.DeconstructInvocationOpt == null) { // tuple case AccessTupleFields(node, deconstruction, temps, stores, placeholders); } else { CallDeconstruct(node, deconstruction, temps, stores, placeholders); } } }
/// <summary> /// Prepares local variables to be used in Deconstruct call /// Adds a invocation of Deconstruct with those as out parameters onto the 'stores' sequence /// Returns the expressions for those out parameters /// </summary> private void CallDeconstruct(BoundDeconstructionAssignmentOperator node, BoundDeconstructionDeconstructStep deconstruction, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders) { Debug.Assert((object)deconstruction.DeconstructInvocationOpt != null); CSharpSyntaxNode syntax = node.Syntax; // prepare out parameters for Deconstruct var deconstructParameters = deconstruction.OutputPlaceholders; var outParametersBuilder = ArrayBuilder<BoundExpression>.GetInstance(deconstructParameters.Length); for (var i = 0; i < deconstructParameters.Length; i++) { var deconstructParameter = deconstructParameters[i]; var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, deconstructParameter.Type, SynthesizedLocalKind.LoweringTemp); var localBound = new BoundLocal(syntax, localSymbol, null, deconstructParameter.Type ) { WasCompilerGenerated = true }; temps.Add(localSymbol); outParametersBuilder.Add(localBound); AddPlaceholderReplacement(deconstruction.OutputPlaceholders[i], localBound); placeholders.Add(deconstruction.OutputPlaceholders[i]); } var outParameters = outParametersBuilder.ToImmutableAndFree(); // invoke Deconstruct with placeholders replaced by locals stores.Add(VisitExpression(deconstruction.DeconstructInvocationOpt)); }
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) { return this.SetMayHaveSideEffects(); }
/// <summary> /// Applies the assignments. /// Adds any new expressions to be evaluated to the stores. /// </summary> private void ApplyAssignments(BoundDeconstructionAssignmentOperator node, ArrayBuilder<BoundExpression> stores, ImmutableArray<BoundExpression> lhsTargets) { int numAssignments = node.AssignmentSteps.Length; for (int i = 0; i < numAssignments; i++) { var assignmentInfo = node.AssignmentSteps[i]; AddPlaceholderReplacement(assignmentInfo.OutputPlaceholder, lhsTargets[i]); var assignment = assignmentInfo.Assignment; // All the input placeholders for the assignments should already be set with lowered nodes Debug.Assert(assignment.Left.Kind == BoundKind.DeconstructValuePlaceholder); Debug.Assert(assignment.Right.Kind == BoundKind.DeconstructValuePlaceholder); var rewrittenLeft = (BoundExpression)Visit(assignment.Left); var rewrittenRight = (BoundExpression)Visit(assignment.Right); var loweredAssignment = MakeAssignmentOperator(assignment.Syntax, rewrittenLeft, rewrittenRight, assignment.Type, used: true, isChecked: false, isCompoundAssignment: false); RemovePlaceholderReplacement(assignmentInfo.OutputPlaceholder); stores.Add(loweredAssignment); } }
/// <summary> /// Makes an expression that constructs the return value for the deconstruction. /// For d-declarations, that is simply void. /// For d-assignments, that is a series of tuple constructions, that are chained with the help of placeholders. /// The placeholders that are set are added to the list for later clearing. /// </summary> private BoundExpression MakeReturnValue(BoundDeconstructionAssignmentOperator node, ArrayBuilder<BoundValuePlaceholderBase> placeholders) { if (node.IsDeclaration) { return new BoundVoid(node.Syntax, node.Type); } BoundExpression loweredConstruction = null; foreach (var constructionInfo in node.ConstructionStepsOpt) { // All the input placeholders for the constructions should already be set loweredConstruction = (BoundExpression)Visit(constructionInfo.Construct); AddPlaceholderReplacement(constructionInfo.OutputPlaceholder, loweredConstruction); placeholders.Add(constructionInfo.OutputPlaceholder); } Debug.Assert(loweredConstruction != null); return loweredConstruction; }
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) { // For deconstruction declarations, the BoundLocals in the LeftVariables should not be added to the map if (!node.IsDeclaration) { VisitList(node.LeftVariables); } Visit(node.Right); // don't map the deconstruction, conversion or assignment steps return null; }
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) { return(this.SetMayHaveSideEffects()); }
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node) { VisitList(node.LeftVariables); Visit(node.Right); // don't map the deconstruction, conversion or assignment steps return null; }