@@ -1909,12 +1909,25 @@ export class Compiler extends DiagnosticEmitter {
19091909 var outerFlow = this . currentFlow ;
19101910 var label = outerFlow . pushBreakLabel ( ) ;
19111911 var innerFlow = outerFlow . fork ( ) ;
1912- this . currentFlow = innerFlow ;
19131912 var breakLabel = "break|" + label ;
19141913 innerFlow . breakLabel = breakLabel ;
19151914 var continueLabel = "continue|" + label ;
19161915 innerFlow . continueLabel = continueLabel ;
19171916
1917+ // Compile the condition before the body in order to...
1918+ var condFlow = outerFlow . fork ( ) ;
1919+ this . currentFlow = condFlow ;
1920+ var condExpr = module . precomputeExpression (
1921+ this . makeIsTrueish (
1922+ this . compileExpression ( statement . condition , Type . i32 ) ,
1923+ this . currentType
1924+ )
1925+ ) ;
1926+ assert ( ! condFlow . hasScopedLocals ) ;
1927+ // ...unify local states before and after the condition has been executed the first time
1928+ innerFlow . unifyLocalFlags ( condFlow ) ;
1929+ this . currentFlow = innerFlow ;
1930+
19181931 var stmts = new Array < ExpressionRef > ( ) ;
19191932 if ( statement . statement . kind == NodeKind . BLOCK ) {
19201933 this . compileStatements ( ( < BlockStatement > statement . statement ) . statements , false , stmts ) ;
@@ -1923,12 +1936,6 @@ export class Compiler extends DiagnosticEmitter {
19231936 this . compileStatement ( statement . statement )
19241937 ) ;
19251938 }
1926- var condExpr = module . precomputeExpression (
1927- this . makeIsTrueish (
1928- this . compileExpression ( statement . condition , Type . i32 ) ,
1929- this . currentType
1930- )
1931- ) ;
19321939 var alwaysFalse = false ;
19331940 if ( getExpressionId ( condExpr ) == ExpressionId . Const ) {
19341941 assert ( getExpressionType ( condExpr ) == NativeType . I32 ) ;
@@ -1946,8 +1953,11 @@ export class Compiler extends DiagnosticEmitter {
19461953 // )
19471954 var fallsThrough = ! terminates && ! innerFlow . is ( FlowFlags . BREAKS ) ;
19481955
1949- if ( fallsThrough && ! alwaysFalse ) { // (4)
1950- stmts . push ( module . br ( continueLabel , condExpr ) ) ;
1956+ if ( fallsThrough ) {
1957+ this . performAutoreleases ( innerFlow , stmts ) ;
1958+ if ( ! alwaysFalse ) { // (4)
1959+ stmts . push ( module . br ( continueLabel , condExpr ) ) ;
1960+ }
19511961 }
19521962 var expr = flatten ( module , stmts , NativeType . None ) ;
19531963 if ( fallsThrough && ! alwaysFalse || continues ) { // (2)
@@ -1958,7 +1968,6 @@ export class Compiler extends DiagnosticEmitter {
19581968 }
19591969
19601970 // Switch back to the parent flow
1961- if ( ! terminates ) this . performAutoreleases ( innerFlow , stmts ) ;
19621971 innerFlow . freeScopedLocals ( ) ;
19631972 outerFlow . popBreakLabel ( ) ;
19641973 innerFlow . unset (
@@ -2030,16 +2039,26 @@ export class Compiler extends DiagnosticEmitter {
20302039 }
20312040 innerFlow . inheritNonnullIfTrue ( condExpr ) ;
20322041
2033- // Compile incrementor
2042+ // Compile the incrementor before the body in order to...
20342043 var incrementor = statement . incrementor ;
20352044 var incrExpr : ExpressionRef = 0 ;
2036- if ( incrementor ) incrExpr = this . compileExpression ( incrementor , Type . void , Constraints . CONV_IMPLICIT | Constraints . WILL_DROP ) ;
2045+ if ( incrementor ) {
2046+ let incrFlow = innerFlow . fork ( ) ;
2047+ this . currentFlow = incrFlow ;
2048+ incrExpr = this . compileExpression ( incrementor , Type . void , Constraints . CONV_IMPLICIT | Constraints . WILL_DROP ) ;
2049+ assert ( ! incrFlow . hasScopedLocals ) ;
2050+ this . currentFlow = innerFlow ;
2051+ // ...unify local states before and after the incrementor has been executed the first time
2052+ innerFlow . unifyLocalFlags ( incrFlow ) ;
2053+ }
20372054
20382055 // Compile body (break: drop out, continue: fall through to incrementor, + loop)
2039- var breakLabel = innerFlow . breakLabel = "break|" + label ; innerFlow . breakLabel = breakLabel ;
2040- innerFlow . breakLabel = breakLabel ;
2056+ var bodyFlow = innerFlow . fork ( ) ;
2057+ this . currentFlow = bodyFlow ;
2058+ var breakLabel = innerFlow . breakLabel = "break|" + label ; bodyFlow . breakLabel = breakLabel ;
2059+ bodyFlow . breakLabel = breakLabel ;
20412060 var continueLabel = "continue|" + label ;
2042- innerFlow . continueLabel = continueLabel ;
2061+ bodyFlow . continueLabel = continueLabel ;
20432062 var loopLabel = "loop|" + label ;
20442063 var bodyStatement = statement . statement ;
20452064 var stmts = new Array < ExpressionRef > ( ) ;
@@ -2048,9 +2067,16 @@ export class Compiler extends DiagnosticEmitter {
20482067 } else {
20492068 stmts . push ( this . compileStatement ( bodyStatement ) ) ;
20502069 }
2051- var terminates = innerFlow . is ( FlowFlags . TERMINATES ) ;
2052- var continues = innerFlow . isAny ( FlowFlags . CONTINUES | FlowFlags . CONDITIONALLY_CONTINUES ) ;
2053- var breaks = innerFlow . isAny ( FlowFlags . BREAKS | FlowFlags . CONDITIONALLY_BREAKS ) ;
2070+ var terminates = bodyFlow . is ( FlowFlags . TERMINATES ) ;
2071+ var continues = bodyFlow . isAny ( FlowFlags . CONTINUES | FlowFlags . CONDITIONALLY_CONTINUES ) ;
2072+ var breaks = bodyFlow . isAny ( FlowFlags . BREAKS | FlowFlags . CONDITIONALLY_BREAKS ) ;
2073+ var fallsThrough = ! terminates && ! innerFlow . is ( FlowFlags . BREAKS ) ;
2074+
2075+ // Finalize body flow
2076+ if ( fallsThrough ) this . performAutoreleases ( bodyFlow , stmts ) ;
2077+ bodyFlow . freeScopedLocals ( ) ;
2078+ innerFlow . inherit ( bodyFlow ) ;
2079+ this . currentFlow = innerFlow ;
20542080
20552081 // (block $break ;; (1) skip label (needed anyway) if skipping (4) + no breaks
20562082 // (initializer) ;; (2) [may be empty]
@@ -2063,7 +2089,6 @@ export class Compiler extends DiagnosticEmitter {
20632089 // (br $loop) ;; (8) skip if skipping (3)
20642090 // )
20652091 // )
2066- var fallsThrough = ! terminates && ! innerFlow . is ( FlowFlags . BREAKS ) ;
20672092 var needsLabel = ! alwaysTrue || breaks ;
20682093
20692094 var loop = new Array < ExpressionRef > ( ) ;
0 commit comments