From 73c08381da9683a7cb9412b307b539a9bd9da0f2 Mon Sep 17 00:00:00 2001
From: Rich-Harris <richard.a.harris@gmail.com>
Date: Sat, 3 Oct 2015 22:34:58 -0400
Subject: [PATCH] mark side-effects that apply to included declarations

---
 src/Bundle.js    | 11 ++++++++---
 src/Module.js    |  6 +++++-
 src/Statement.js | 17 +++++++++++++----
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/Bundle.js b/src/Bundle.js
index 25831b8..f8408cc 100644
--- a/src/Bundle.js
+++ b/src/Bundle.js
@@ -55,9 +55,14 @@ export default class Bundle {
 					module.bindReferences();
 				});
 
-				this.modules.forEach( module => {
-					module.markAllSideEffects();
-				});
+				let settled = false;
+				while ( !settled ) {
+					settled = true;
+
+					this.modules.forEach( module => {
+						if ( module.markAllSideEffects() ) settled = false;
+					});
+				}
 
 				// mark all export statements
 				entryModule.getExports().forEach( name => {
diff --git a/src/Module.js b/src/Module.js
index 6cc27da..9569878 100644
--- a/src/Module.js
+++ b/src/Module.js
@@ -297,9 +297,13 @@ export default class Module {
 	}
 
 	markAllSideEffects () {
+		let hasSideEffect = false;
+
 		this.statements.forEach( statement => {
-			statement.markSideEffect();
+			if ( statement.markSideEffect() ) hasSideEffect = true;
 		});
+
+		return hasSideEffect;
 	}
 
 	parse ( ast ) {
diff --git a/src/Statement.js b/src/Statement.js
index fe1682c..f7b6f28 100644
--- a/src/Statement.js
+++ b/src/Statement.js
@@ -107,7 +107,7 @@ export default class Statement {
 					this.skip(); // don't descend from `foo.bar.baz` into `foo.bar`
 				}
 			},
-			leave: ( node ) => {
+			leave ( node ) {
 				if ( node._scope ) scope = scope.parent;
 			}
 		});
@@ -125,7 +125,10 @@ export default class Statement {
 	}
 
 	markSideEffect () {
+		if ( this.isIncluded ) return;
+
 		const statement = this;
+		let hasSideEffect = false;
 
 		walk( this.node, {
 			enter ( node, parent ) {
@@ -134,7 +137,7 @@ export default class Statement {
 				// If this is a top-level call expression, or an assignment to a global,
 				// this statement will need to be marked
 				if ( node.type === 'CallExpression' || node.type === 'NewExpression' ) {
-					statement.mark();
+					hasSideEffect = true;
 				}
 
 				else if ( node.type in modifierNodes ) {
@@ -143,11 +146,17 @@ export default class Statement {
 
 					const declaration = statement.module.trace( subject.name );
 
-					// global
-					if ( !declaration ) statement.mark();
+					if ( !declaration || declaration.statement.isIncluded ) {
+						hasSideEffect = true;
+					}
 				}
+
+				if ( hasSideEffect ) this.skip();
 			}
 		});
+
+		if ( hasSideEffect ) statement.mark();
+		return hasSideEffect;
 	}
 
 	source () {