/// <summary> /// Add sequence point |here|: /// /// |foreach| (Type var in expr) { } /// </summary> /// <remarks> /// Hit once, before looping begins. /// </remarks> private void AddForEachKeywordSequencePoint(ForEachStatementSyntax forEachSyntax, ref BoundStatement result) { if (this.GenerateDebugInfo) { BoundSequencePointWithSpan foreachKeywordSequencePoint = new BoundSequencePointWithSpan(forEachSyntax, null, forEachSyntax.ForEachKeyword.Span); result = new BoundStatementList(forEachSyntax, ImmutableArray.Create<BoundStatement>(foreachKeywordSequencePoint, result)); } }
/// <summary> /// Lower a foreach loop that will enumerate a single-dimensional array. /// /// A[] a = x; /// for (int p = 0; p < a.Length; p = p + 1) { /// V v = (V)a[p]; /// // body /// } /// </summary> /// <remarks> /// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's /// implementation of IEnumerable and just indexing into its elements. /// /// NOTE: We're assuming that sequence points have already been generated. /// Otherwise, lowering to for-loops would generated spurious ones. /// </remarks> private BoundStatement RewriteSingleDimensionalArrayForEachStatement(BoundForEachStatement node) { ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax; BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node); Debug.Assert(collectionExpression.Type.IsArray()); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type; Debug.Assert(arrayType.IsSZArray); TypeSymbol intType = _compilation.GetSpecialType(SpecialType.System_Int32); TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression); BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body); // A[] a LocalSymbol arrayVar = _factory.SynthesizedLocal(arrayType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArray); // A[] a = /*node.Expression*/; BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression); AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl); // Reference to a. BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType); // int p LocalSymbol positionVar = _factory.SynthesizedLocal(intType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArrayIndex); // Reference to p. BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType); // int p = 0; BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar, MakeLiteral(forEachSyntax, ConstantValue.Default(SpecialType.System_Int32), intType)); // V v LocalSymbol iterationVar = node.IterationVariable; TypeSymbol iterationVarType = iterationVar.Type; // (V)a[p] BoundExpression iterationVarInitValue = MakeConversion( syntax: forEachSyntax, rewrittenOperand: new BoundArrayAccess( syntax: forEachSyntax, expression: boundArrayVar, indices: ImmutableArray.Create<BoundExpression>(boundPositionVar), type: arrayType.ElementType), conversion: node.ElementConversion, rewrittenType: iterationVarType, @checked: node.Checked); // V v = (V)a[p]; BoundStatement iterationVariableDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue); AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVariableDecl); BoundStatement initializer = new BoundStatementList(forEachSyntax, statements: ImmutableArray.Create<BoundStatement>(arrayVarDecl, positionVarDecl)); // a.Length BoundExpression arrayLength = new BoundArrayLength( syntax: forEachSyntax, expression: boundArrayVar, type: intType); // p < a.Length BoundExpression exitCondition = new BoundBinaryOperator( syntax: forEachSyntax, operatorKind: BinaryOperatorKind.IntLessThan, left: boundPositionVar, right: arrayLength, constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType); // p = p + 1; BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType); // { V v = (V)a[p]; /* node.Body */ } BoundStatement loopBody = CreateBlockDeclaringIterationVariable(iterationVar, iterationVariableDecl, rewrittenBody, forEachSyntax); // for (A[] a = /*node.Expression*/, int p = 0; p < a.Length; p = p + 1) { // V v = (V)a[p]; // /*node.Body*/ // } BoundStatement result = RewriteForStatement( syntax: node.Syntax, outerLocals: ImmutableArray.Create<LocalSymbol>(arrayVar, positionVar), rewrittenInitializer: initializer, rewrittenCondition: exitCondition, conditionSyntaxOpt: null, conditionSpanOpt: forEachSyntax.InKeyword.Span, rewrittenIncrement: positionIncrement, rewrittenBody: loopBody, breakLabel: node.BreakLabel, continueLabel: node.ContinueLabel, hasErrors: node.HasErrors); AddForEachKeywordSequencePoint(forEachSyntax, ref result); return result; }
/// <summary> /// Lower a foreach loop that will enumerate the characters of a string. /// /// string s = x; /// for (int p = 0; p < s.Length; p = p + 1) { /// V v = (V)s.Chars[p]; /// // body /// } /// </summary> /// <remarks> /// We will follow Dev10 in diverging from the C# 4 spec by ignoring string's /// implementation of IEnumerable and just indexing into its characters. /// /// NOTE: We're assuming that sequence points have already been generated. /// Otherwise, lowering to for-loops would generated spurious ones. /// </remarks> private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node) { ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax; BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node); TypeSymbol stringType = collectionExpression.Type; Debug.Assert(stringType.SpecialType == SpecialType.System_String); TypeSymbol intType = _compilation.GetSpecialType(SpecialType.System_Int32); TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression); BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body); // string s; LocalSymbol stringVar = _factory.SynthesizedLocal(stringType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArray); // int p; LocalSymbol positionVar = _factory.SynthesizedLocal(intType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArrayIndex); // Reference to s. BoundLocal boundStringVar = MakeBoundLocal(forEachSyntax, stringVar, stringType); // Reference to p. BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType); // string s = /*expr*/; BoundStatement stringVarDecl = MakeLocalDeclaration(forEachSyntax, stringVar, rewrittenExpression); AddForEachExpressionSequencePoint(forEachSyntax, ref stringVarDecl); // int p = 0; BoundStatement positionVariableDecl = MakeLocalDeclaration(forEachSyntax, positionVar, MakeLiteral(forEachSyntax, ConstantValue.Default(SpecialType.System_Int32), intType)); // string s = /*node.Expression*/; int p = 0; BoundStatement initializer = new BoundStatementList(forEachSyntax, statements: ImmutableArray.Create<BoundStatement>(stringVarDecl, positionVariableDecl)); MethodSymbol method = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_String__Length); BoundExpression stringLength = BoundCall.Synthesized( syntax: forEachSyntax, receiverOpt: boundStringVar, method: method, arguments: ImmutableArray<BoundExpression>.Empty); // p < s.Length BoundExpression exitCondition = new BoundBinaryOperator( syntax: forEachSyntax, operatorKind: BinaryOperatorKind.IntLessThan, left: boundPositionVar, right: stringLength, constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType); // p = p + 1; BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType); LocalSymbol iterationVar = node.IterationVariable; TypeSymbol iterationVarType = iterationVar.Type; Debug.Assert(node.ElementConversion.IsValid); // (V)s.Chars[p] MethodSymbol chars = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_String__Chars); BoundExpression iterationVarInitValue = MakeConversion( syntax: forEachSyntax, rewrittenOperand: BoundCall.Synthesized( syntax: forEachSyntax, receiverOpt: boundStringVar, method: chars, arguments: ImmutableArray.Create<BoundExpression>(boundPositionVar)), conversion: node.ElementConversion, rewrittenType: iterationVarType, @checked: node.Checked); // V v = (V)s.Chars[p]; BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue); AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl); // { V v = (V)s.Chars[p]; /*node.Body*/ } BoundStatement loopBody = CreateBlockDeclaringIterationVariable(iterationVar, iterationVarDecl, rewrittenBody, forEachSyntax); // for (string s = /*node.Expression*/, int p = 0; p < s.Length; p = p + 1) { // V v = (V)s.Chars[p]; // /*node.Body*/ // } BoundStatement result = RewriteForStatement( syntax: forEachSyntax, outerLocals: ImmutableArray.Create(stringVar, positionVar), rewrittenInitializer: initializer, rewrittenCondition: exitCondition, conditionSyntaxOpt: null, conditionSpanOpt: forEachSyntax.InKeyword.Span, rewrittenIncrement: positionIncrement, rewrittenBody: loopBody, breakLabel: node.BreakLabel, continueLabel: node.ContinueLabel, hasErrors: node.HasErrors); AddForEachKeywordSequencePoint(forEachSyntax, ref result); return result; }
/// <summary> /// Lower a foreach loop that will enumerate the characters of a string. /// /// string s = x; /// for (int p = 0; p < s.Length; p = p + 1) { /// V v = (V)s.Chars[p]; /// // body /// } /// </summary> /// <remarks> /// We will follow Dev10 in diverging from the C# 4 spec by ignoring string's /// implementation of IEnumerable and just indexing into its characters. /// /// NOTE: We're assuming that sequence points have already been generated. /// Otherwise, lowering to for-loops would generated spurious ones. /// </remarks> private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node) { ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax; BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node); TypeSymbol stringType = collectionExpression.Type; Debug.Assert(stringType.SpecialType == SpecialType.System_String); TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32); TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression); BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body); // string s; LocalSymbol stringVar = factory.SynthesizedLocal(stringType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArray); // int p; LocalSymbol positionVar = factory.SynthesizedLocal(intType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArrayIndex0); // Reference to s. BoundLocal boundStringVar = MakeBoundLocal(forEachSyntax, stringVar, stringType); // Reference to p. BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType); // string s = /*expr*/; BoundStatement stringVarDecl = MakeLocalDeclaration(forEachSyntax, stringVar, rewrittenExpression); AddForEachExpressionSequencePoint(forEachSyntax, ref stringVarDecl); // int p = 0; BoundStatement positionVariableDecl = MakeLocalDeclaration(forEachSyntax, positionVar, MakeLiteral(forEachSyntax, ConstantValue.Default(SpecialType.System_Int32), intType)); // string s = /*node.Expression*/; int p = 0; BoundStatement initializer = new BoundStatementList(forEachSyntax, statements: ImmutableArray.Create <BoundStatement>(stringVarDecl, positionVariableDecl)); MethodSymbol method = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_String__Length); BoundExpression stringLength = BoundCall.Synthesized( syntax: forEachSyntax, receiverOpt: boundStringVar, method: method, arguments: ImmutableArray <BoundExpression> .Empty); // p < s.Length BoundExpression exitCondition = new BoundBinaryOperator( syntax: forEachSyntax, operatorKind: BinaryOperatorKind.IntLessThan, left: boundPositionVar, right: stringLength, constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType); // p = p + 1; BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType); LocalSymbol iterationVar = node.IterationVariable; TypeSymbol iterationVarType = iterationVar.Type; Debug.Assert(node.ElementConversion.IsValid); // (V)s.Chars[p] MethodSymbol chars = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_String__Chars); BoundExpression iterationVarInitValue = MakeConversion( syntax: forEachSyntax, rewrittenOperand: BoundCall.Synthesized( syntax: forEachSyntax, receiverOpt: boundStringVar, method: chars, arguments: ImmutableArray.Create <BoundExpression>(boundPositionVar)), conversion: node.ElementConversion, rewrittenType: iterationVarType, @checked: node.Checked); // V v = (V)s.Chars[p]; BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue); AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl); // { V v = (V)s.Chars[p]; /*node.Body*/ } BoundStatement loopBody = new BoundBlock(forEachSyntax, locals: ImmutableArray.Create <LocalSymbol>(iterationVar), statements: ImmutableArray.Create <BoundStatement>(iterationVarDecl, rewrittenBody)); // for (string s = /*node.Expression*/, int p = 0; p < s.Length; p = p + 1) { // V v = (V)s.Chars[p]; // /*node.Body*/ // } BoundStatement result = RewriteForStatement( syntax: forEachSyntax, outerLocals: ImmutableArray.Create(stringVar, positionVar), rewrittenInitializer: initializer, rewrittenCondition: exitCondition, conditionSyntaxOpt: null, conditionSpanOpt: forEachSyntax.InKeyword.Span, rewrittenIncrement: positionIncrement, rewrittenBody: loopBody, breakLabel: node.BreakLabel, continueLabel: node.ContinueLabel, hasErrors: node.HasErrors); AddForEachKeywordSequencePoint(forEachSyntax, ref result); return(result); }
/// <summary> /// Lower a foreach loop that will enumerate a single-dimensional array. /// /// A[] a = x; /// for (int p = 0; p < a.Length; p = p + 1) { /// V v = (V)a[p]; /// // body /// } /// </summary> /// <remarks> /// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's /// implementation of IEnumerable and just indexing into its elements. /// /// NOTE: We're assuming that sequence points have already been generated. /// Otherwise, lowering to for-loops would generated spurious ones. /// </remarks> private BoundStatement RewriteSingleDimensionalArrayForEachStatement(BoundForEachStatement node) { ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax; BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node); Debug.Assert(collectionExpression.Type.IsArray()); ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type; Debug.Assert(arrayType.Rank == 1); TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32); TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression); BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body); // A[] a LocalSymbol arrayVar = factory.SynthesizedLocal(arrayType, syntax: forEachSyntax, tempKind: TempKind.ForEachArray); // A[] a = /*node.Expression*/; BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression); AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl); // Reference to a. BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType); // int p LocalSymbol positionVar = factory.SynthesizedLocal(intType, syntax: forEachSyntax, tempKind: TempKind.ForEachArrayIndex0); // Reference to p. BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType); // int p = 0; BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar, MakeLiteral(forEachSyntax, ConstantValue.Default(SpecialType.System_Int32), intType)); // V v LocalSymbol iterationVar = node.IterationVariable; TypeSymbol iterationVarType = iterationVar.Type; // (V)a[p] BoundExpression iterationVarInitValue = MakeConversion( syntax: forEachSyntax, rewrittenOperand: new BoundArrayAccess( syntax: forEachSyntax, expression: boundArrayVar, indices: ImmutableArray.Create <BoundExpression>(boundPositionVar), type: arrayType.ElementType), conversion: node.ElementConversion, rewrittenType: iterationVarType, @checked: node.Checked); // V v = (V)a[p]; BoundStatement iterationVariableDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue); AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVariableDecl); BoundStatement initializer = new BoundStatementList(forEachSyntax, statements: ImmutableArray.Create <BoundStatement>(arrayVarDecl, positionVarDecl)); // a.Length BoundExpression arrayLength = new BoundArrayLength( syntax: forEachSyntax, expression: boundArrayVar, type: intType); // p < a.Length BoundExpression exitCondition = new BoundBinaryOperator( syntax: forEachSyntax, operatorKind: BinaryOperatorKind.IntLessThan, left: boundPositionVar, right: arrayLength, constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType); // p = p + 1; BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType); // { V v = (V)a[p]; /* node.Body */ } BoundStatement loopBody = new BoundBlock(forEachSyntax, localsOpt: ImmutableArray.Create <LocalSymbol>(iterationVar), statements: ImmutableArray.Create <BoundStatement>(iterationVariableDecl, rewrittenBody)); // for (A[] a = /*node.Expression*/, int p = 0; p < a.Length; p = p + 1) { // V v = (V)a[p]; // /*node.Body*/ // } BoundStatement result = RewriteForStatement( syntax: node.Syntax, locals: ImmutableArray.Create <LocalSymbol>(arrayVar, positionVar), rewrittenInitializer: initializer, rewrittenCondition: exitCondition, conditionSyntax: forEachSyntax.InKeyword, rewrittenIncrement: positionIncrement, rewrittenBody: loopBody, breakLabel: node.BreakLabel, continueLabel: node.ContinueLabel, hasErrors: node.HasErrors); AddForEachKeywordSequencePoint(forEachSyntax, ref result); return(result); }
public override BoundNode VisitExpressionStatement(BoundExpressionStatement node) { // NOTE: not using a BoundNoOpStatement, since we don't want a nop to be emitted. // CONSIDER: could use a BoundNoOpStatement (DevDiv #12943). return(RewriteExpressionStatement(node) ?? BoundStatementList.Synthesized(node.Syntax)); }