anchor.diff:    TreeNode visitForInStatement(ForInStatement stmt) {
       return _lowerForIn(stmt);
     }
  +
  +  StaticInvocation _completerBoolInitializer() => StaticInvocation(
  +      coreTypes.index.getProcedure('dart:async', 'Completer', ''),
  +      Arguments([], types: [coreTypes.boolNonNullableRawType]));
  +
  +  InstanceInvocation _addToController(
  +      VariableDeclaration controller, Expression expression, int fileOffset) {
  +    Procedure controllerAdd =
  +        coreTypes.index.getProcedure('dart:async', 'StreamController', 'add');
  +    FunctionType controllerAddType =
  +        Substitution.fromInterfaceType(controllerNullableObjectType)
  +                .substituteType(controllerAdd.function
  +                    .computeThisFunctionType(Nullability.nonNullable))
  +            as FunctionType;
  +    return InstanceInvocation(InstanceAccessKind.Instance,
  +        VariableGet(controller), Name('add'), Arguments([expression]),
  +        interfaceTarget: controllerAdd, functionType: controllerAddType)
  +      ..fileOffset = fileOffset;
  +  }
  +
  +  InstanceInvocation _addCompleterToController(VariableDeclaration controller,
  +          VariableDeclaration completer, int fileOffset) =>
  +      _addToController(controller, VariableGet(completer), fileOffset);
  +
  +  AwaitExpression _awaitCompleterFuture(
  +      VariableDeclaration completer, int fileOffset) {
  +    Procedure completerFuture =
  +        coreTypes.index.getProcedure('dart:async', 'Completer', 'get:future');
  +    FunctionType completerFutureType =
  +        Substitution.fromInterfaceType(completerBoolType).substituteType(
  +                completerFuture.function
  +                    .computeThisFunctionType(Nullability.nonNullable))
  +            as FunctionType;
  +    return AwaitExpression(InstanceGet(
  +        InstanceAccessKind.Instance, VariableGet(completer), Name('future'),
  +        interfaceTarget: completerFuture, resultType: completerFutureType)
  +      ..fileOffset = fileOffset);
  +  }
  +
  +  TreeNode _lowerAsyncStar(FunctionNode functionNode) {
  +    // TODO(joshualitt): This lowering is mostly reasonable, but if possible we
  +    // should try and figure out a way to remove the even / odd dance. That
  +    // said, this will be replaced by an intrinsic implemntation ASAP so it may
  +    // not be worth spending anymore time on this(aside from bug fixes).
  +    //
  +    // Transform
  +    //
  +    //   Stream<T> foo() async* {
  +    //     ...
  +    //     yield i;
  +    //     ...
  +    //     yield* bar;
  +    //     ...
  +    //   }
  +    //
  +    // Into
  +    //
  +    //   Stream<T> foo() {
  +    //     StreamController<Object?> #controller = StreamController<Object?>();
  +    //     Future<void> Function() #body = () async {
  +    //       Completer<bool> #completer = Completer<bool>();
  +    //       #controller.add(#completer);
  +    //       await #completer.future;
  +    //       ...
  +    //       #controller.add(i);
  +    //       #completer = Completer<bool>();
  +    //       #controller.add(#completer)
  +    //       await #completer.future;
  +    //       ...
  +    //       await for (var i in bar) {
  +    //         #controller.add(i);
  +    //         #completer = Completer<bool>();
  +    //         #controller.add(#completer)
  +    //         await #completer.future;
  +    //       }
  +    //       ...
  +    //       #controller.close();
  +    //     };
  +    //     bool isEven = false;
  +    //     bool isFirst = true;
  +    //     #controller.add(null);
  +    //     return #controller.stream.asyncMap((value) async {
  +    //       if (first) {
  +    //         #body();
  +    //         return null;
  +    //       }
  +    //       if (value is Completer<Bool>) {
  +    //         value.complete(true);
  +    //       }
  +    //       return value;
  +    //     }).where((value) {
  +    //       if (first) {
  +    //         first = false;
  +    //         return false;
  +    //       }
  +    //       bool keep = even;
  +    //       even = !even;
  +    //       return keep;
  +    //     }).cast<T>();
  +    //   }
  +    int fileOffset = functionNode.fileOffset;
  +
  +    // Initialize `#controller`.
  +    final controllerInitializer = StaticInvocation(
  +        coreTypes.index.getProcedure('dart:async', 'StreamController', ''),
  +        Arguments([], types: [coreTypes.objectNullableRawType]));
  +    final controller = VariableDeclaration('#controller',
  +        initializer: controllerInitializer..fileOffset = fileOffset,
  +        type: controllerNullableObjectType)
  +      ..fileOffset = fileOffset;
  +
  +    // Initialize `#completer`.
  +    final completer = VariableDeclaration('#completer',
  +        initializer: _completerBoolInitializer()..fileOffset = fileOffset,
  +        type: completerBoolType)
  +      ..fileOffset = fileOffset;
  +
  +    // Close `#controller`.
  +    Procedure controllerCloseProc =
  +        coreTypes.index.getProcedure('dart:async', 'StreamController', 'close');
  +    FunctionType controllerCloseType =
  +        Substitution.fromInterfaceType(controllerNullableObjectType)
  +                .substituteType(controllerCloseProc.function
  +                    .computeThisFunctionType(Nullability.nonNullable))
  +            as FunctionType;
  +    final callControllerClose = InstanceInvocation(InstanceAccessKind.Instance,
  +        VariableGet(controller), Name('close'), Arguments([]),
  +        interfaceTarget: controllerCloseProc,
  +        functionType: controllerCloseType);
  +
  +    // Create a frame so yield statements within the body can access the right
  +    // controller / completer.
  +    _asyncStarFrames.add(_AsyncStarFrame(controller, completer));
  +
  +    // Visit the body to transform any yields. We will re-visit after
  +    // transformation just to ensure everything we've added will also be
  +    // lowered.
  +    Statement? transformedBody =
  +        functionNode.body?.accept<TreeNode>(this) as Statement?;
  +    _asyncStarFrames.removeLast();
  +
  +    // Locally declare body function.
  +    final bodyFunction = FunctionNode(
  +        Block([
  +          completer,
  +          ExpressionStatement(
  +              _addCompleterToController(controller, completer, fileOffset)),
  +          ExpressionStatement(_awaitCompleterFuture(completer, fileOffset)),
  +          if (transformedBody != null) transformedBody,
  +          ExpressionStatement(callControllerClose),
  +        ]),
  +        futureValueType: const VoidType(),
  +        returnType: InterfaceType(
  +            coreTypes.futureClass, Nullability.nonNullable, [const VoidType()]),
  +        asyncMarker: AsyncMarker.Async,
  +        dartAsyncMarker: AsyncMarker.Async);
  +    final bodyInitializer = FunctionExpression(bodyFunction);
  +    FunctionType bodyFunctionType =
  +        bodyFunction.computeThisFunctionType(Nullability.nonNullable);
  +    final body = VariableDeclaration('#body',
  +        initializer: bodyInitializer..fileOffset = fileOffset,
  +        type: bodyFunctionType)
  +      ..fileOffset = fileOffset;
  +
  +    // Invoke body.
  +    final invokeBody = FunctionInvocation(
  +        FunctionAccessKind.FunctionType, VariableGet(body), Arguments([]),
  +        functionType: bodyFunctionType);
  +
  +    // Create a 'counting' sentinel to let us know which values to filter.
  +    final isEven = VariableDeclaration('#isEven',
  +        initializer: ConstantExpression(BoolConstant(false))
  +          ..fileOffset = fileOffset,
  +        type: coreTypes.boolNonNullableRawType)
  +      ..fileOffset = fileOffset;
  +    final isFirst = VariableDeclaration('#isFirst',
  +        initializer: ConstantExpression(BoolConstant(true))
  +          ..fileOffset = fileOffset,
  +        type: coreTypes.boolNonNullableRawType)
  +      ..fileOffset = fileOffset;
  +
  +    // Get `controller.stream`
  +    Procedure controllerStream = coreTypes.index
  +        .getProcedure('dart:async', 'StreamController', 'get:stream');
  +    FunctionType controllerStreamType =
  +        Substitution.fromInterfaceType(controllerNullableObjectType)
  +                .substituteType(controllerStream.function
  +                    .computeThisFunctionType(Nullability.nonNullable))
  +            as FunctionType;
  +    final getControllerStream = InstanceGet(
  +        InstanceAccessKind.Instance, VariableGet(controller), Name('stream'),
  +        interfaceTarget: controllerStream, resultType: controllerStreamType);
  +
  +    // Prepare `completerPrePass` to issue a round of completions to our hidden
  +    // completers.
  +    Procedure completerComplete =
  +        coreTypes.index.getProcedure('dart:async', 'Completer', 'complete');
  +    FunctionType completerCompleteType =
  +        Substitution.fromInterfaceType(completerBoolType).substituteType(
  +                completerComplete.function
  +                    .computeThisFunctionType(Nullability.nonNullable))
  +            as FunctionType;
  +    final completerPrePassArg =
  +        VariableDeclaration('value', type: coreTypes.objectNullableRawType);
  +    final completerPrePass = FunctionExpression(FunctionNode(
  +      Block([
  +        IfStatement(
  +            VariableGet(isFirst),
  +            Block([
  +              ExpressionStatement(invokeBody),
  +              ReturnStatement(ConstantExpression(NullConstant())),
  +            ]),
  +            null),
  +        IfStatement(
  +            IsExpression(VariableGet(completerPrePassArg), completerBoolType),
  +            ExpressionStatement(InstanceInvocation(
  +                InstanceAccessKind.Instance,
  +                VariableGet(completerPrePassArg),
  +                Name('complete'),
  +                Arguments([ConstantExpression(BoolConstant(true))]),
  +                interfaceTarget: completerComplete,
  +                functionType: completerCompleteType)),
  +            null),
  +        ReturnStatement(VariableGet(completerPrePassArg)),
  +      ]),
  +      positionalParameters: [completerPrePassArg],
  +      returnType: FutureOrType(
  +          coreTypes.objectNullableRawType, Nullability.nonNullable),
  +      asyncMarker: AsyncMarker.Async,
  +      dartAsyncMarker: AsyncMarker.Async,
  +      futureValueType: coreTypes.objectNullableRawType,
  +    ));
  +
  +    // Call `asyncMap`.
  +    Procedure asyncMap =
  +        coreTypes.index.getProcedure('dart:async', 'Stream', 'asyncMap');
  +    final streamType = InterfaceType(coreTypes.streamClass,
  +        Nullability.nonNullable, [coreTypes.objectNullableRawType]);
  +    final asyncMapType = FunctionType([
  +      FunctionType([
  +        coreTypes.objectNullableRawType
  +      ], FutureOrType(coreTypes.objectNullableRawType, Nullability.nonNullable),
  +          Nullability.nonNullable, requiredParameterCount: 1)
  +    ], streamType, Nullability.nonNullable, requiredParameterCount: 1);
  +    final callAsyncMap = InstanceInvocation(
  +        InstanceAccessKind.Instance,
  +        getControllerStream,
  +        Name('asyncMap'),
  +        Arguments([completerPrePass], types: [coreTypes.objectNullableRawType]),
  +        interfaceTarget: asyncMap,
  +        functionType: asyncMapType);
  +
  +    // Call `where`.
  +    final whereFilterArg =
  +        VariableDeclaration('value', type: coreTypes.objectNullableRawType);
  +    final whereKeep = VariableDeclaration('keep',
  +        initializer: VariableGet(isEven),
  +        type: coreTypes.boolNonNullableRawType);
  +
  +    final whereFilter = FunctionExpression(FunctionNode(
  +        Block([
  +          IfStatement(
  +              VariableGet(isFirst),
  +              Block([
  +                ExpressionStatement(VariableSet(
  +                    isFirst, ConstantExpression(BoolConstant(false)))),
  +                ReturnStatement(ConstantExpression(BoolConstant(false)))
  +              ]),
  +              null),
  +          whereKeep,
  +          ExpressionStatement(VariableSet(isEven, Not(VariableGet(isEven)))),
  +          ReturnStatement(VariableGet(whereKeep)),
  +        ]),
  +        positionalParameters: [whereFilterArg],
  +        returnType: coreTypes.objectNullableRawType));
  +
  +    Procedure whereProc =
  +        coreTypes.index.getProcedure('dart:async', 'Stream', 'where');
  +    FunctionType whereProcType = Substitution.fromInterfaceType(streamType)
  +        .substituteType(whereProc.function
  +            .computeThisFunctionType(Nullability.nonNullable)) as FunctionType;
  +    final callWhere = InstanceInvocation(InstanceAccessKind.Instance,
  +        callAsyncMap, Name('where'), Arguments([whereFilter]),
  +        interfaceTarget: whereProc, functionType: whereProcType);
  +
  +    // Finally call cast
  +    DartType typeArgument;
  +    if (functionNode.returnType is InterfaceType) {
  +      typeArgument =
  +          (functionNode.returnType as InterfaceType).typeArguments.single;
  +    } else {
  +      typeArgument = const DynamicType();
  +    }
  +    Procedure castProc =
  +        coreTypes.index.getProcedure('dart:async', 'Stream', 'cast');
  +    final returnStreamType = InterfaceType(
  +        coreTypes.streamClass, typeArgument.nullability, [typeArgument]);
  +    final castProcType = FunctionType(
  +        [], returnStreamType, Nullability.nonNullable,
  +        requiredParameterCount: 1);
  +    final castToExpectedType = InstanceInvocation(InstanceAccessKind.Instance,
  +        callWhere, Name('cast'), Arguments([], types: [typeArgument]),
  +        interfaceTarget: castProc, functionType: castProcType);
  +    return FunctionNode(
  +        Block([
  +          controller,
  +          body,
  +          isFirst,
  +          isEven,
  +          ExpressionStatement(_addToController(
  +              controller, ConstantExpression(NullConstant()), fileOffset)),
  +          ReturnStatement(castToExpectedType),
  +        ]),
  +        typeParameters: functionNode.typeParameters,
  +        positionalParameters: functionNode.positionalParameters,
  +        namedParameters: functionNode.namedParameters,
  +        requiredParameterCount: functionNode.requiredParameterCount,
  +        returnType: functionNode.returnType,
  +        asyncMarker: AsyncMarker.Sync,
  +        dartAsyncMarker: AsyncMarker.Sync);
  +  }
  +
  +  @override
  +  TreeNode visitYieldStatement(YieldStatement yield) {
  +    // We currently ignore yields in 'sync*'.
  +    if (!_enclosingIsAsyncStar) {
  +      return super.visitYieldStatement(yield);
  +    }
  +    int fileOffset = yield.fileOffset;
  +    _AsyncStarFrame frame = _asyncStarFrames.last;
  +    VariableDeclaration controller = frame.controller;
  +    VariableDeclaration completer = frame.completer;
  +    bool isYieldStar = yield.isYieldStar;
  +
  +    // If [isYieldStar] then we need to create an `await for` loop to wrap the
  +    // yields.
  +    DartType yieldExpressionType = yield.expression.getStaticType(typeContext);
  +    VariableDeclaration? awaitForVar;
  +    if (isYieldStar) {
  +      DartType awaitVarType = const DynamicType();
  +      if (yieldExpressionType is InterfaceType) {
  +        Class cls = yieldExpressionType.className.asClass;
  +        if (cls == coreTypes.streamClass) {
  +          awaitVarType = yieldExpressionType.typeArguments.single;
  +        }
  +      }
  +      awaitForVar = VariableDeclaration('#awaitForVar', type: awaitVarType)
  +        ..fileOffset = fileOffset;
  +    }
  +
  +    final yieldBody = Block([
  +      ExpressionStatement(_addToController(
  +          controller,
  +          isYieldStar ? VariableGet(awaitForVar!) : yield.expression,
  +          fileOffset)),
  +      ExpressionStatement(VariableSet(completer, _completerBoolInitializer())),
  +      ExpressionStatement(
  +          _addCompleterToController(controller, completer, fileOffset)),
  +      ExpressionStatement(_awaitCompleterFuture(completer, fileOffset)),
  +    ]);
  +    if (isYieldStar) {
  +      // If this is a yield* then wrap the yield in an `await for`.
  +      ForInStatement awaitForIn = ForInStatement(
  +          awaitForVar!, yield.expression, yieldBody,
  +          isAsync: true);
  +      return awaitForIn.accept<TreeNode>(this);
  +    } else {
  +      return yieldBody.accept<TreeNode>(this);
  +    }
  +  }
  +
  +  @override
  +  TreeNode visitFunctionNode(FunctionNode functionNode) {
  +    if (functionNode.dartAsyncMarker == AsyncMarker.AsyncStar) {
  +      _enclosingIsAsyncStar = true;
  +      functionNode = _lowerAsyncStar(functionNode) as FunctionNode;
  +      _enclosingIsAsyncStar = false;
  +      return super.visitFunctionNode(functionNode);
  +    } else {
  +      bool previousEnclosing = _enclosingIsAsyncStar;
  +      TreeNode result = super.visitFunctionNode(functionNode);
  +      _enclosingIsAsyncStar = previousEnclosing;
  +      return result;
  +    }
  +  }
   }
  +
  +class _AsyncStarFrame {
  +  final VariableDeclaration controller;
  +  final VariableDeclaration completer;
  +
  +  _AsyncStarFrame(this.controller, this.completer);
  +}
  
positive.code: import 'package:kernel/class_hierarchy.dart';
  import 'package:kernel/core_types.dart';
  import 'package:kernel/type_environment.dart';
  
  void transformLibraries(
      List<Library> libraries, CoreTypes coreTypes, ClassHierarchy hierarchy) {
  
negative.code:   StaticTypeContext? _cachedTypeContext;
    final Library _coreLibrary;
    final InterfaceType _nonNullableTypeType;
    final List<_AsyncStarFrame> _asyncStarFrames = [];
    bool _enclosingIsAsyncStar = false;
    late final controllerNullableObjectType = InterfaceType(
        coreTypes.index.getClass('dart:async', 'StreamController'),
        Nullability.nonNullable,
        [coreTypes.objectNullableRawType]);
    late final completerBoolType = InterfaceType(
        coreTypes.index.getClass('dart:async', 'Completer'),
        Nullability.nonNullable,
        [coreTypes.boolNonNullableRawType]);
  
    StaticTypeContext get typeContext =>
        _cachedTypeContext ??= StaticTypeContext(_currentMember!, env);
  