diff --git a/src/core/IronPython/Compiler/Ast/ForStatement.cs b/src/core/IronPython/Compiler/Ast/ForStatement.cs index bb18f05c6..d90bb8c46 100644 --- a/src/core/IronPython/Compiler/Ast/ForStatement.cs +++ b/src/core/IronPython/Compiler/Ast/ForStatement.cs @@ -74,18 +74,26 @@ internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.Param ) ); - // while enumerator.MoveNext(): - // left = enumerator.Current + // iterator = enumerator.Key + // read once, because the interpreter calls a property getter of a struct through reflection + MSAst.ParameterExpression iterator = Ast.Variable(typeof(IEnumerator), "foreach_iterator"); + MSAst.Expression initIterator = Ast.Assign( + iterator, + Ast.Property( + enumerator, + typeof(KeyValuePair).GetProperty("Key") + ) + ); + + // while iterator.MoveNext(): + // left = iterator.Current // body // else: // else MSAst.Expression ls = AstUtils.Loop( parent.GlobalParent.AddDebugInfo( Ast.Call( - Ast.Property( - enumerator, - typeof(KeyValuePair).GetProperty("Key") - ), + iterator, typeof(IEnumerator).GetMethod("MoveNext") ), left.Span @@ -95,10 +103,7 @@ internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.Param left.TransformSet( SourceSpan.None, Ast.Call( - Ast.Property( - enumerator, - typeof(KeyValuePair).GetProperty("Key") - ), + iterator, typeof(IEnumerator).GetProperty("Current").GetGetMethod() ), PythonOperationKind.None @@ -113,12 +118,15 @@ internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.Param ); return Ast.Block( + [iterator], init, + initIterator, Ast.TryFinally( ls, Ast.Block( Ast.Call(AstMethods.ForLoopDispose, enumerator), - Ast.Assign(enumerator, Ast.New(typeof(KeyValuePair))) + Ast.Assign(enumerator, Ast.New(typeof(KeyValuePair))), + Ast.Assign(iterator, AstUtils.Constant(null, typeof(IEnumerator))) ) ) );