anchor.diff:        //   promotes x, but not y or z
         // }
         var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      var y = h.addAssignedVar('y', 'int?');
  -      var z = h.addAssignedVar('z', 'int?');
  -      h.ifElse(
  -          h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
  -              h.or(h.eqNull(x), h.eqNull(z))),
  -          () {}, () {
  -        expect(h.flow.promotedType(x).type, 'int');
  -        expect(h.flow.promotedType(y), isNull);
  -        expect(h.flow.promotedType(z), isNull);
  -      });
  -      h.flow.finish();
  +      var x = h.addVar('x', 'int?');
  +      var y = h.addVar('y', 'int?');
  +      var z = h.addVar('z', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        h.declare(y, initialized: true);
  +        h.declare(z, initialized: true);
  +        h.ifElse(
  +            h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
  +                h.or(h.eqNull(x), h.eqNull(z))),
  +            () {}, () {
  +          expect(flow.promotedType(x).type, 'int');
  +          expect(flow.promotedType(y), isNull);
  +          expect(flow.promotedType(z), isNull);
  +        });
  +      });
       });
   
       test('conditionEqNull(notEqual: true) promotes true branch', () {
         var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        var expr = _Expression();
  +        flow.conditionEqNull(expr, x, notEqual: true);
  +        flow.ifStatement_thenBegin(expr);
  +        expect(flow.promotedType(x).type, 'int');
  +        flow.ifStatement_elseBegin();
  +        expect(flow.promotedType(x), isNull);
  +        flow.ifStatement_end(true);
  +      });
  +    });
  +
  +    test('conditionEqNull(notEqual: false) promotes false branch', () {
  +      var h = _Harness();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        var expr = _Expression();
  +        flow.conditionEqNull(expr, x, notEqual: false);
  +        flow.ifStatement_thenBegin(expr);
  +        expect(flow.promotedType(x), isNull);
  +        flow.ifStatement_elseBegin();
  +        expect(flow.promotedType(x).type, 'int');
  +        flow.ifStatement_end(true);
  +      });
  +    });
  +
  +    test('doStatement_bodyBegin() un-promotes', () {
  +      var h = _Harness();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        h.promote(x, 'int');
  +        expect(flow.promotedType(x).type, 'int');
  +        flow.doStatement_bodyBegin(_Statement(), {x});
  +        expect(flow.promotedType(x), isNull);
  +        flow.doStatement_conditionBegin();
  +        flow.doStatement_end(_Expression());
  +      });
  +    });
  +
  +    test('doStatement_conditionBegin() joins continue state', () {
  +      var h = _Harness();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        var stmt = _Statement();
  +        flow.doStatement_bodyBegin(stmt, {});
  +        h.if_(h.notNull(x), () {
  +          flow.handleContinue(stmt);
  +        });
  +        flow.handleExit();
  +        expect(flow.isReachable, false);
  +        expect(flow.promotedType(x), isNull);
  +        flow.doStatement_conditionBegin();
  +        expect(flow.isReachable, true);
  +        expect(flow.promotedType(x).type, 'int');
  +        flow.doStatement_end(_Expression());
  +      });
  +    });
  +
  +    test('doStatement_end() promotes', () {
  +      var h = _Harness();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        flow.doStatement_bodyBegin(_Statement(), {});
  +        flow.doStatement_conditionBegin();
  +        expect(flow.promotedType(x), isNull);
  +        flow.doStatement_end(h.eqNull(x)());
  +        expect(flow.promotedType(x).type, 'int');
  +      });
  +    });
  +
  +    test('finish checks proper nesting', () {
  +      var h = _Harness();
         var expr = _Expression();
  -      h.flow.conditionEqNull(expr, x, notEqual: true);
  -      h.flow.ifStatement_thenBegin(expr);
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.ifStatement_elseBegin();
  -      expect(h.flow.promotedType(x), isNull);
  -      h.flow.ifStatement_end(true);
  -      h.flow.finish();
  -    });
  -
  -    test('conditionEqNull(notEqual: false) promotes false branch', () {
  -      var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      var expr = _Expression();
  -      h.flow.conditionEqNull(expr, x, notEqual: false);
  -      h.flow.ifStatement_thenBegin(expr);
  -      expect(h.flow.promotedType(x), isNull);
  -      h.flow.ifStatement_elseBegin();
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.ifStatement_end(true);
  -      h.flow.finish();
  -    });
  -
  -    test('doStatement_bodyBegin() un-promotes', () {
  -      var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      h.promote(x, 'int');
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.doStatement_bodyBegin(_Statement(), {x});
  -      expect(h.flow.promotedType(x), isNull);
  -      h.flow.doStatement_conditionBegin();
  -      h.flow.doStatement_end(_Expression());
  -      h.flow.finish();
  -    });
  -
  -    test('doStatement_conditionBegin() joins continue state', () {
  -      var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      var stmt = _Statement();
  -      h.flow.doStatement_bodyBegin(stmt, {});
  -      h.if_(h.notNull(x), () {
  -        h.flow.handleContinue(stmt);
  -      });
  -      h.flow.handleExit();
  -      expect(h.flow.isReachable, false);
  -      expect(h.flow.promotedType(x), isNull);
  -      h.flow.doStatement_conditionBegin();
  -      expect(h.flow.isReachable, true);
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.doStatement_end(_Expression());
  -      h.flow.finish();
  -    });
  -
  -    test('doStatement_end() promotes', () {
  -      var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      h.flow.doStatement_bodyBegin(_Statement(), {});
  -      h.flow.doStatement_conditionBegin();
  -      expect(h.flow.promotedType(x), isNull);
  -      h.flow.doStatement_end(h.eqNull(x)());
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.finish();
  -    });
  -
  -    test('finish checks proper nesting', () {
  -      var h = _Harness();
  -      var expr = _Expression();
  -      h.flow.ifStatement_thenBegin(expr);
  -      expect(() => h.flow.finish(), _asserts);
  +      var flow = h.createFlow();
  +      flow.ifStatement_thenBegin(expr);
  +      expect(() => flow.finish(), _asserts);
       });
   
       test('finish checks for un-added variables', () {
         var h = _Harness();
         var x = _Var('x', _Type('int'));
  -      h.flow.isAssigned(x);
  -      expect(() => h.flow.finish(), _asserts);
  +      var flow = h.createFlow();
  +      flow.isAssigned(x);
  +      expect(() => flow.finish(), _asserts);
       });
   
       test('for_conditionBegin() un-promotes', () {
         var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      h.promote(x, 'int');
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.for_conditionBegin({x});
  -      expect(h.flow.promotedType(x), isNull);
  -      h.flow.for_bodyBegin(_Statement(), _Expression());
  -      h.flow.for_updaterBegin();
  -      h.flow.for_end();
  -      h.flow.finish();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        h.promote(x, 'int');
  +        expect(flow.promotedType(x).type, 'int');
  +        flow.for_conditionBegin({x});
  +        expect(flow.promotedType(x), isNull);
  +        flow.for_bodyBegin(_Statement(), _Expression());
  +        flow.for_updaterBegin();
  +        flow.for_end();
  +      });
       });
   
       test('for_conditionBegin() handles not-yet-seen variables', () {
         var h = _Harness();
  -      var x = _Var('x', _Type('int?'));
  -      var y = h.addAssignedVar('y', 'int?');
  -      h.promote(y, 'int');
  -      h.flow.for_conditionBegin({x});
  -      h.flow.add(x, assigned: true);
  -      h.flow.for_bodyBegin(_Statement(), _Expression());
  -      h.flow.for_updaterBegin();
  -      h.flow.for_end();
  -      h.flow.finish();
  +      var x = h.addVar('x', 'int?');
  +      var y = h.addVar('y', 'int?');
  +      h.run((flow) {
  +        h.declare(y, initialized: true);
  +        h.promote(y, 'int');
  +        flow.for_conditionBegin({x});
  +        flow.add(x, assigned: true);
  +        flow.for_bodyBegin(_Statement(), _Expression());
  +        flow.for_updaterBegin();
  +        flow.for_end();
  +      });
       });
   
       test('for_bodyBegin() handles empty condition', () {
         var h = _Harness();
  -      h.flow.for_conditionBegin({});
  -      h.flow.for_bodyBegin(_Statement(), null);
  -      h.flow.for_updaterBegin();
  -      expect(h.flow.isReachable, isTrue);
  -      h.flow.for_end();
  -      expect(h.flow.isReachable, isFalse);
  -      h.flow.finish();
  +      h.run((flow) {
  +        flow.for_conditionBegin({});
  +        flow.for_bodyBegin(_Statement(), null);
  +        flow.for_updaterBegin();
  +        expect(flow.isReachable, isTrue);
  +        flow.for_end();
  +        expect(flow.isReachable, isFalse);
  +      });
       });
   
       test('for_bodyBegin() promotes', () {
         var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      h.flow.for_conditionBegin({});
  -      h.flow.for_bodyBegin(_Statement(), h.notNull(x)());
  -      expect(h.flow.promotedType(x).type, 'int');
  -      h.flow.for_updaterBegin();
  -      h.flow.for_end();
  -      h.flow.finish();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        flow.for_conditionBegin({});
  +        flow.for_bodyBegin(_Statement(), h.notNull(x)());
  +        expect(flow.promotedType(x).type, 'int');
  +        flow.for_updaterBegin();
  +        flow.for_end();
  +      });
       });
   
       test('for_bodyBegin() can be used with a null statement', () {
         // This is needed for collection elements that are for-loops.
         var h = _Harness();
  -      var x = h.addAssignedVar('x', 'int?');
  -      h.flow.for_conditionBegin({});
  -      h.flow.for_bodyBegin(null, h.notNull(x)());
  -      h.flow.for_updaterBegin();
  -      h.flow.for_end();
  -      h.flow.finish();
  +      var x = h.addVar('x', 'int?');
  +      h.run((flow) {
  +        h.declare(x, initialized: true);
  +        flow.for_conditionBegin({});
  +        flow.for_bodyBegin(null, h.notNull(x)());
  +        flow.for_updaterBegin();
  +        flow.for_end();
  +      });
       });
   
       test('for_updaterBegin() joins current and continue states', () {
  
positive.code:       //   promotes x and y
        // }
        var h = _Harness();
        var x = h.addAssignedVar('x', 'int?');
        var y = h.addAssignedVar('y', 'int?');
        h.ifElse(h.or(h.eqNull(x), h.eqNull(y)), () {}, () {
          expect(h.flow.promotedType(x).type, 'int');
          expect(h.flow.promotedType(y).type, 'int');
        });
        h.flow.finish();
      });
  
      test('promotedType handles not-yet-seen variables', () {
        // Note: this is needed for error recovery in the analyzer.
        var h = _Harness();
        var x = _Var('x', _Type('int'));
        expect(h.flow.promotedType(x), isNull);
      });
  
      test('switchStatement_beginCase(false) restores previous promotions', () {
        var h = _Harness();
        var x = h.addAssignedVar('x', 'int?');
        h.promote(x, 'int');
        h.flow.switchStatement_expressionEnd(_Statement());
        h.flow.switchStatement_beginCase(false, {x});
        expect(h.flow.promotedType(x).type, 'int');
        h.flow.write(x);
        expect(h.flow.promotedType(x), isNull);
        h.flow.switchStatement_beginCase(false, {x});
        expect(h.flow.promotedType(x).type, 'int');
        h.flow.write(x);
        expect(h.flow.promotedType(x), isNull);
        h.flow.switchStatement_end(false);
        h.flow.finish();
      });
  
      test('switchStatement_beginCase(false) does not un-promote', () {
        var h = _Harness();
        var x = h.addAssignedVar('x', 'int?');
        h.promote(x, 'int');
        h.flow.switchStatement_expressionEnd(_Statement());
        h.flow.switchStatement_beginCase(false, {x});
        expect(h.flow.promotedType(x).type, 'int');
        h.flow.write(x);
        expect(h.flow.promotedType(x), isNull);
        h.flow.switchStatement_end(false);
        h.flow.finish();
      });
  
      test('switchStatement_beginCase(true) un-promotes', () {
        var h = _Harness();
        var x = h.addAssignedVar('x', 'int?');
        h.promote(x, 'int');
        h.flow.switchStatement_expressionEnd(_Statement());
        h.flow.switchStatement_beginCase(true, {x});
        expect(h.flow.promotedType(x), isNull);
        h.flow.write(x);
        expect(h.flow.promotedType(x), isNull);
        h.flow.switchStatement_end(false);
        h.flow.finish();
      });
  
      test('switchStatement_end(false) joins break and default', () {
        var h = _Harness();
        var x = h.addAssignedVar('x', 'int?');
        var y = h.addAssignedVar('y', 'int?');
        var z = h.addAssignedVar('z', 'int?');
        h.promote(y, 'int');
        h.promote(z, 'int');
        var stmt = _Statement();
        h.flow.switchStatement_expressionEnd(stmt);
        h.flow.switchStatement_beginCase(false, {y});
        h.promote(x, 'int');
        h.flow.write(y);
        h.flow.handleBreak(stmt);
        h.flow.switchStatement_end(false);
        expect(h.flow.promotedType(x), isNull);
        expect(h.flow.promotedType(y), isNull);
        expect(h.flow.promotedType(z).type, 'int');
        h.flow.finish();
      });
  
      test('switchStatement_end(true) joins breaks', () {
        var h = _Harness();
        var w = h.addAssignedVar('w', 'int?');
        var x = h.addAssignedVar('x', 'int?');
        var y = h.addAssignedVar('y', 'int?');
        var z = h.addAssignedVar('z', 'int?');
        h.promote(x, 'int');
        h.promote(y, 'int');
        h.promote(z, 'int');
        var stmt = _Statement();
        h.flow.switchStatement_expressionEnd(stmt);
        h.flow.switchStatement_beginCase(false, {x, y});
        h.promote(w, 'int');
        h.promote(y, 'int');
        h.flow.write(x);
        h.flow.handleBreak(stmt);
        h.flow.switchStatement_beginCase(false, {x, y});
        h.promote(w, 'int');
        h.promote(x, 'int');
        h.flow.write(y);
        h.flow.handleBreak(stmt);
        h.flow.switchStatement_end(true);
        expect(h.flow.promotedType(w).type, 'int');
        expect(h.flow.promotedType(x), isNull);
        expect(h.flow.promotedType(y), isNull);
        expect(h.flow.promotedType(z).type, 'int');
        h.flow.finish();
      });
  
      test('switchStatement_end(true) allows fall-through of last case', () {
        var h = _Harness();
        var x = h.addAssignedVar('x', 'int?');
        var stmt = _Statement();
        h.flow.switchStatement_expressionEnd(stmt);
        h.flow.switchStatement_beginCase(false, {});
        h.promote(x, 'int');
        h.flow.handleBreak(stmt);
        h.flow.switchStatement_beginCase(false, {});
        h.flow.switchStatement_end(true);
        expect(h.flow.promotedType(x), isNull);
        h.flow.finish();
      });
  
      test('Infinite loop does not implicitly assign variables', () {
        var h = _Harness();
        var x = h.addUnassignedVar('x', 'int');
        var trueCondition = _Expression();
        h.flow.whileStatement_conditionBegin({x});
        h.flow.booleanLiteral(trueCondition, true);
        h.flow.whileStatement_bodyBegin(_Statement(), trueCondition);
        h.flow.whileStatement_end();
        expect(h.flow.isAssigned(x), false);
      });
  
      test('If(false) does not discard promotions', () {
        var h = _Harness();
        var x = h.addAssignedVar('x', 'Object');
        h.promote(x, 'int');
        expect(h.flow.promotedType(x).type, 'int');
        // if (false) {
        var falseExpression = _Expression();
        h.flow.booleanLiteral(falseExpression, false);
        h.flow.ifStatement_thenBegin(falseExpression);
        expect(h.flow.promotedType(x).type, 'int');
        h.flow.ifStatement_end(false);
      });
    });
  
  
negative.code:         NodeOperations<_Expression>,
          TypeOperations<_Var, _Type>,
          FunctionBodyAccess<_Var> {
    FlowAnalysis<_Statement, _Expression, _Var, _Type> _flow;
  
    /// Returns a [LazyExpression] representing an expression with now special
    /// flow analysis semantics.
    LazyExpression get expr => () => _Expression();
  
    _Var addVar(String name, String type) {
      assert(_flow == null);
      return _Var(name, _Type(type));
    }
  
    /// Given two [LazyExpression]s, produces a new [LazyExpression] representing
  