public override void VisitForeachStatement(ForeachStatement foreachStatement) {
			var ferr = (ForEachResolveResult)_resolver.Resolve(foreachStatement);
			var iterator = (LocalResolveResult)_resolver.Resolve(foreachStatement.VariableNameToken);

			var getEnumeratorMethod = (ferr.GetEnumeratorCall is InvocationResolveResult ? ((InvocationResolveResult)ferr.GetEnumeratorCall).Member as IMethod : null);

			var systemArray = _compilation.FindType(KnownTypeCode.Array);
			var inExpression = ResolveWithConversion(foreachStatement.InExpression);
			if (Equals(inExpression.Type, systemArray) || inExpression.Type.DirectBaseTypes.Contains(systemArray) || (getEnumeratorMethod != null && _metadataImporter.GetMethodSemantics(getEnumeratorMethod).EnumerateAsArray)) {
				var arrayResult = CompileExpression(foreachStatement.InExpression, CompileExpressionFlags.ReturnValueIsImportant);
				_result.AddRange(arrayResult.AdditionalStatements);
				var array = arrayResult.Expression;
				if (IsJsExpressionComplexEnoughToGetATemporaryVariable.Analyze(array)) {
					var tmpArray = CreateTemporaryVariable(ferr.CollectionType, foreachStatement.GetRegion());
					_result.Add(JsStatement.Var(_variables[tmpArray].Name, array));
					array = JsExpression.Identifier(_variables[tmpArray].Name);
				}

				var length = systemArray.GetProperties().SingleOrDefault(p => p.Name == "Length");
				if (length == null) {
					_errorReporter.InternalError("Property Array.Length not found.");
					return;
				}
				var lengthSem = _metadataImporter.GetPropertySemantics(length);
				if (lengthSem.Type != PropertyScriptSemantics.ImplType.Field) {
					_errorReporter.InternalError("Property Array.Length is not implemented as a field.");
					return;
				}

				var index = CreateTemporaryVariable(_compilation.FindType(KnownTypeCode.Int32), foreachStatement.GetRegion());
				var jsIndex = JsExpression.Identifier(_variables[index].Name);
				JsExpression iteratorValue = MaybeCloneValueType(JsExpression.Index(array, jsIndex), null, ferr.ElementType);
				if (_variables[iterator.Variable].UseByRefSemantics)
					iteratorValue = JsExpression.ObjectLiteral(new JsObjectLiteralProperty("$", iteratorValue));

				var body = new[] { JsStatement.Var(_variables[iterator.Variable].Name, iteratorValue) }
				          .Concat(CreateInnerCompiler().Compile(foreachStatement.EmbeddedStatement).Statements);

				_result.Add(JsStatement.For(JsStatement.Var(_variables[index].Name, JsExpression.Number(0)),
				                            JsExpression.Lesser(jsIndex, JsExpression.Member(array, lengthSem.FieldName)),
				                            JsExpression.PostfixPlusPlus(jsIndex),
				                            JsStatement.Block(body)));
			}
			else {
				var getEnumeratorCall = _expressionCompiler.Compile(ferr.GetEnumeratorCall, true);
				_result.AddRange(getEnumeratorCall.AdditionalStatements);
				var enumerator = CreateTemporaryVariable(ferr.EnumeratorType, foreachStatement.GetRegion());
				_result.Add(JsStatement.Var(_variables[enumerator].Name, getEnumeratorCall.Expression));

				var moveNextInvocation = _expressionCompiler.Compile(new CSharpInvocationResolveResult(new LocalResolveResult(enumerator), ferr.MoveNextMethod, new ResolveResult[0]), true);
				if (moveNextInvocation.AdditionalStatements.Count > 0)
					_errorReporter.InternalError("MoveNext() invocation is not allowed to require additional statements.");

				var getCurrent = _expressionCompiler.Compile(new MemberResolveResult(new LocalResolveResult(enumerator), ferr.CurrentProperty), true);
				JsExpression getCurrentValue = MaybeCloneValueType(getCurrent.Expression, null, ferr.ElementType);
				if (_variables[iterator.Variable].UseByRefSemantics)
					getCurrentValue = JsExpression.ObjectLiteral(new JsObjectLiteralProperty("$", getCurrentValue));

				var preBody = getCurrent.AdditionalStatements.Concat(new[] { JsStatement.Var(_variables[iterator.Variable].Name, getCurrentValue) }).ToList();
				var body = CreateInnerCompiler().Compile(foreachStatement.EmbeddedStatement);

				body = JsStatement.Block(preBody.Concat(body.Statements));

				JsStatement disposer;

				var systemIDisposable = _compilation.FindType(KnownTypeCode.IDisposable);
				var disposeMethod = systemIDisposable.GetMethods().Single(m => m.Name == "Dispose");
				var conversions = CSharpConversions.Get(_compilation);
				var disposableConversion = conversions.ImplicitConversion(enumerator.Type, systemIDisposable);
				if (disposableConversion.IsValid) {
					// If the enumerator is implicitly convertible to IDisposable, we should dispose it.
					var compileResult = _expressionCompiler.Compile(new CSharpInvocationResolveResult(new ConversionResolveResult(systemIDisposable, new LocalResolveResult(enumerator), disposableConversion), disposeMethod, new ResolveResult[0]), false);
					if (compileResult.AdditionalStatements.Count != 0)
						_errorReporter.InternalError("Call to IDisposable.Dispose must not return additional statements.");
					disposer = compileResult.Expression;
				}
				else if (enumerator.Type.GetDefinition().IsSealed) {
					// If the enumerator is sealed and not implicitly convertible to IDisposable, we need not dispose it.
					disposer = null;
				}
				else {
					// We don't know whether the enumerator is convertible to IDisposable, so we need to conditionally dispose it.
					var test = _expressionCompiler.Compile(new TypeIsResolveResult(new LocalResolveResult(enumerator), systemIDisposable, _compilation.FindType(KnownTypeCode.Boolean)), true);
					if (test.AdditionalStatements.Count > 0)
						_errorReporter.InternalError("\"is\" test must not return additional statements.");
					var innerStatements = _expressionCompiler.Compile(new CSharpInvocationResolveResult(new ConversionResolveResult(systemIDisposable, new LocalResolveResult(enumerator), conversions.ExplicitConversion(enumerator.Type, systemIDisposable)), disposeMethod, new ResolveResult[0]), false);
					disposer = JsStatement.If(test.Expression, JsStatement.Block(innerStatements.AdditionalStatements.Concat(new JsStatement[] { innerStatements.Expression })), null);
				}
				JsStatement stmt = JsStatement.While(moveNextInvocation.Expression, body);
				if (disposer != null)
					stmt = JsStatement.Try(stmt, null, disposer);
				_result.Add(stmt);
			}
		}