anchor.diff:    }
   }
   
  +/// Informs about which libraries, classes, and members should be retained by
  +/// the [_KernelOutlineShaker] when tree-shaking.
  +abstract class _RetainedData {
  +  /// Whether a class should be preserved. If a class is preserved, its
  +  /// supertypes will be preserved too, but some of it members may not be
  +  /// included.
  +  bool isClassUsed(Class cls);
  +
  +  /// Whether the field initializer should be preserved.
  +  bool isFieldInitializerUsed(Field node);
  +
  +  /// Whether a library should be preserved and mark as external.
  +  bool isLibraryUsed(Library library);
  +
  +  /// Whether a member should be preserved. If so, its enclosing class/library
  +  /// will be preserved too.
  +  bool isMemberUsed(Member member);
  +
  +  /// Whether the parameter initializer should be preserved.
  +  bool isParameterInitializerUsed(VariableDeclaration node);
  +
  +  /// Whether a typedef should be preserved. If a typedef is preserved, its
  +  /// return type and types of parameters will be preserved too.
  +  bool isTypedefUsed(Typedef node);
  +}
  +
  +/// A builder of [_RetainedData] that recursively marks transitive dependencies.
  +///
  +/// When it is used as a [RecursiveVisitor], it recursively marks nodes that
  +/// are references by visited nodes.
  +class _RetainedDataBuilder extends RecursiveVisitor implements _RetainedData {
  +  /// Libraries that contained code that is transitively reachable from the
  +  /// included libraries.
  +  final Set<Library> libraries = new Set<Library>();
  +
  +  /// Classes that are transitively reachable from the included libraries.
  +  final Set<Class> classes = new Set<Class>();
  +
  +  /// Typedefs that are transitively reachable from the included libraries.
  +  final Set<Typedef> typedefs = new Set<Typedef>();
  +
  +  /// Members that are transitively reachable from the included libraries.
  +  final Set<Member> members = new Set<Member>();
  +
  +  /// Fields for which initializers should be kept because they are constants,
  +  /// or are final fields of classes with constant constructors.
  +  final Set<Field> fieldsWithInitializers = new Set<Field>();
  +
  +  /// Parameters for which initializers should be kept because they are
  +  /// parameters of a constant constructors.
  +  final Set<VariableDeclaration> parametersWithInitializers =
  +      new Set<VariableDeclaration>();
  +
  +  _TypeMarker typeMarker;
  +
  +  _RetainedDataBuilder() {
  +    typeMarker = new _TypeMarker(this);
  +  }
  +
  +  @override
  +  bool isClassUsed(Class cls) => classes.contains(cls);
  +
  +  @override
  +  bool isFieldInitializerUsed(Field node) {
  +    return fieldsWithInitializers.contains(node);
  +  }
  +
  +  @override
  +  bool isLibraryUsed(Library library) => libraries.contains(library);
  +
  +  @override
  +  bool isMemberUsed(Member m) => members.contains(m);
  +
  +  @override
  +  bool isParameterInitializerUsed(VariableDeclaration node) {
  +    return parametersWithInitializers.contains(node);
  +  }
  +
  +  @override
  +  bool isTypedefUsed(Typedef node) => typedefs.contains(node);
  +
  +  void markAdditionalExports(Library node) {
  +    for (var reference in node.additionalExports) {
  +      var node = reference.node;
  +      if (node is Class) {
  +        markClassForExport(node);
  +      } else if (node is Member) {
  +        markMember(node);
  +      } else if (node is Typedef) {
  +        markTypedef(node);
  +      } else {
  +        unimplemented('export ${node.runtimeType}', -1, null);
  +      }
  +    }
  +  }
  +
  +  void markAnnotations(List<Expression> annotations) {
  +    for (var annotation in annotations) {
  +      annotation.accept(this);
  +    }
  +  }
  +
  +  /// Mark a class and it's supertypes as used.
  +  void markClass(Class cls) {
  +    if (cls == null || !classes.add(cls)) return;
  +    markLibrary(cls.parent);
  +    markAnnotations(cls.annotations);
  +    cls.typeParameters.forEach((t) => t.bound.accept(typeMarker));
  +    markSupertype(cls.supertype);
  +    markSupertype(cls.mixedInType);
  +    cls.implementedTypes.forEach(markSupertype);
  +
  +    for (var field in cls.fields) {
  +      if (!field.isStatic && !field.name.isPrivate) {
  +        markMember(field);
  +      }
  +    }
  +    for (var method in cls.procedures) {
  +      if (!method.isStatic && !method.name.isPrivate) {
  +        markMember(method);
  +      }
  +    }
  +  }
  +
  +  /// Mark the given class as exported, so mark all its public members.
  +  void markClassForExport(Class node) {
  +    markClass(node);
  +    for (var field in node.fields) {
  +      if (!field.name.isPrivate) {
  +        markMember(field);
  +      }
  +    }
  +    for (var constructor in node.constructors) {
  +      if (!constructor.name.isPrivate) {
  +        markMember(constructor);
  +      }
  +    }
  +    for (var method in node.procedures) {
  +      if (!method.name.isPrivate) {
  +        markMember(method);
  +      }
  +    }
  +  }
  +
  +  /// Mark a library as used.
  +  void markLibrary(Library lib) {
  +    libraries.add(lib);
  +  }
  +
  +  /// Mark a member and types mentioned on its interface.
  +  void markMember(Member node) {
  +    if (node == null || !members.add(node)) return;
  +
  +    var parent = node.parent;
  +    if (parent is Library) {
  +      markLibrary(parent);
  +    } else if (parent is Class) {
  +      markClass(parent);
  +    }
  +
  +    markAnnotations(node.annotations);
  +    markMemberInterface(node);
  +
  +    if (node is Field) {
  +      if (_shouldKeepFieldInitializer(node)) {
  +        fieldsWithInitializers.add(node);
  +        node.initializer?.accept(this);
  +      }
  +    }
  +  }
  +
  +  void markMemberInterface(Member node) {
  +    if (node is Field) {
  +      node.type.accept(typeMarker);
  +    } else if (node is Constructor) {
  +      var function = node.function;
  +      for (var parameter in function.positionalParameters) {
  +        markParameterType(parameter);
  +        if (node.isConst) {
  +          markParameterInitializer(parameter);
  +        }
  +      }
  +      for (var parameter in function.namedParameters) {
  +        markParameterType(parameter);
  +        if (node.isConst) {
  +          markParameterInitializer(parameter);
  +        }
  +      }
  +      // We don't mark automatically all constructors of classes.
  +      // So, we need transitively mark super/redirect initializers.
  +      for (var initializer in node.initializers) {
  +        if (initializer is SuperInitializer) {
  +          markMember(initializer.target);
  +        } else if (initializer is RedirectingInitializer) {
  +          markMember(initializer.target);
  +        }
  +      }
  +    } else if (node is Procedure) {
  +      var function = node.function;
  +      function.typeParameters.forEach((p) => p.bound.accept(typeMarker));
  +      function.positionalParameters.forEach(markParameterType);
  +      function.namedParameters.forEach(markParameterType);
  +      function.returnType.accept(typeMarker);
  +    }
  +  }
  +
  +  void markParameterInitializer(VariableDeclaration parameter) {
  +    parametersWithInitializers.add(parameter);
  +    parameter.initializer?.accept(this);
  +  }
  +
  +  void markParameterType(VariableDeclaration parameter) {
  +    return parameter.type.accept(typeMarker);
  +  }
  +
  +  /// Mark the class and type arguments of [node].
  +  void markSupertype(Supertype node) {
  +    if (node == null) return;
  +    markClass(node.classNode);
  +    node.typeArguments.forEach((t) => t.accept(typeMarker));
  +  }
  +
  +  /// Mark the typedef.
  +  void markTypedef(Typedef node) {
  +    if (node == null || !typedefs.add(node)) return;
  +    markLibrary(node.parent);
  +    markAnnotations(node.annotations);
  +
  +    FunctionType type = node.type;
  +    type.returnType?.accept(typeMarker);
  +    for (var positionalType in type.positionalParameters) {
  +      positionalType.accept(typeMarker);
  +    }
  +    for (var namedType in type.namedParameters) {
  +      namedType.type.accept(typeMarker);
  +    }
  +  }
  +
  +  @override
  +  visitConstructor(Constructor node) {
  +    if (!node.initializers.any((i) => i is SuperInitializer)) {
  +      // super() is currently implicit.
  +      var supertype = node.enclosingClass.supertype;
  +      if (supertype != null) {
  +        for (var constructor in supertype.classNode.constructors) {
  +          if (constructor.name.name == '') markMember(constructor);
  +        }
  +      }
  +    }
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitConstructorInvocation(ConstructorInvocation node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitDirectMethodInvocation(DirectMethodInvocation node) {
  +    if (node.receiver is! ThisExpression) {
  +      return unsupported("direct call not on this", node.fileOffset, null);
  +    }
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitDirectPropertyGet(DirectPropertyGet node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitDirectPropertySet(DirectPropertySet node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitFunctionType(FunctionType node) {
  +    markTypedef(node.typedefReference?.asTypedef);
  +    super.visitFunctionType(node);
  +  }
  +
  +  @override
  +  visitInterfaceType(InterfaceType node) {
  +    markClass(node.classNode);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitLibrary(Library node) {
  +    markAdditionalExports(node);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitMethodInvocation(MethodInvocation node) {
  +    markMember(node.interfaceTarget);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitPropertyGet(PropertyGet node) {
  +    markMember(node.interfaceTarget);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitPropertySet(PropertySet node) {
  +    markMember(node.interfaceTarget);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitRedirectingInitializer(RedirectingInitializer node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitStaticGet(StaticGet node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitStaticInvocation(StaticInvocation node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitStaticSet(StaticSet node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitSuperInitializer(SuperInitializer node) {
  +    markMember(node.target);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitSuperPropertyGet(SuperPropertyGet node) {
  +    markMember(node.interfaceTarget);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitSuperPropertySet(SuperPropertySet node) {
  +    markMember(node.interfaceTarget);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitSupertype(Supertype node) {
  +    markClass(node.classNode);
  +    node.visitChildren(this);
  +  }
  +
  +  @override
  +  visitTypedefReference(Typedef node) {
  +    return unimplemented("visitTypedefReference", -1, null);
  +  }
  +
  +  /// Marks classes and members that are assumed to exist by fasta or by
  +  /// transformers.
  +  // TODO(sigmund): consider being more fine-grained and only marking what is
  +  // seen and used.
  +  void _markRequired(Program program) {
  +    var coreTypes = new CoreTypes(program);
  +    coreTypes.objectClass.members.forEach(markMember);
  +
  +    // These are assumed to be available by fasta:
  +    markClass(coreTypes.objectClass);
  +    markClass(coreTypes.nullClass);
  +    markClass(coreTypes.boolClass);
  +    markClass(coreTypes.intClass);
  +    markClass(coreTypes.numClass);
  +    markClass(coreTypes.doubleClass);
  +    markClass(coreTypes.stringClass);
  +    markClass(coreTypes.listClass);
  +    markClass(coreTypes.mapClass);
  +    markClass(coreTypes.iterableClass);
  +    markClass(coreTypes.iteratorClass);
  +    markClass(coreTypes.futureClass);
  +    markClass(coreTypes.streamClass);
  +    markClass(coreTypes.symbolClass);
  +    markClass(coreTypes.internalSymbolClass);
  +    markClass(coreTypes.typeClass);
  +    markClass(coreTypes.functionClass);
  +    markClass(coreTypes.invocationClass);
  +    markMember(coreTypes.externalNameDefaultConstructor);
  +
  +    // These are needed by the continuation (async/await) transformer:
  +    markClass(coreTypes.iteratorClass);
  +    markClass(coreTypes.futureClass);
  +    markClass(coreTypes.futureOrClass);
  +    markClass(coreTypes.completerClass);
  +    markMember(coreTypes.completerSyncConstructor);
  +    markMember(coreTypes.syncIterableDefaultConstructor);
  +    markMember(coreTypes.streamIteratorDefaultConstructor);
  +    markMember(coreTypes.futureMicrotaskConstructor);
  +    markMember(coreTypes.asyncStarStreamControllerDefaultConstructor);
  +    markMember(coreTypes.printProcedure);
  +    markMember(coreTypes.asyncThenWrapperHelperProcedure);
  +    markMember(coreTypes.asyncErrorWrapperHelperProcedure);
  +    markMember(coreTypes.awaitHelperProcedure);
  +
  +    // These are needed by the mixin transformer
  +    markMember(coreTypes.invocationMirrorDefaultConstructor);
  +    markMember(coreTypes.listFromConstructor);
  +  }
  +
  +  static bool _shouldKeepFieldInitializer(Field node) {
  +    if (node.isConst) return true;
  +    if (node.isFinal && !node.isStatic) {
  +      var parent = node.parent;
  +      if (parent is Class) {
  +        for (var constructor in parent.constructors) {
  +          if (constructor.isConst) return true;
  +        }
  +      }
  +    }
  +    return false;
  +  }
  +}
  +
   /// [BinaryPrinter] that serializes outlines of all nodes in included
  -/// libraries, and outlines of nodes that are marked in the [RetainedData].
  -class TrimmedBinaryPrinter extends BinaryPrinter {
  +/// libraries, and outlines of nodes that are marked in the [_RetainedData].
  +class _TrimmedBinaryPrinter extends BinaryPrinter {
     final bool Function(Uri uri) isIncluded;
  -  final RetainedData data;
  -  List<Library> librariesToWrite = <Library>[];
  +  final _RetainedData data;
  +  final List<Library> librariesToWrite = <Library>[];
     bool insideIncludedLibrary = false;
   
  -  TrimmedBinaryPrinter(Sink<List<int>> sink, this.isIncluded, this.data)
  +  _TrimmedBinaryPrinter(Sink<List<int>> sink, this.isIncluded, this.data)
         : super(sink);
   
     @override
  -  void writeLibraries(Program program) {
  -    for (var library in program.libraries) {
  -      if (isIncluded(library.importUri) || data.isLibraryUsed(library)) {
  -        librariesToWrite.add(library);
  -      }
  -    }
  -    writeList(librariesToWrite, writeNode);
  -  }
  -
  -  @override
  -  void writeProgramIndex(Program program, List<Library> libraries) {
  -    super.writeProgramIndex(program, librariesToWrite);
  +  visitClass(Class node) {
  +    var level = node.level;
  +    node.level = ClassLevel.Hierarchy;
  +    super.visitClass(node);
  +    node.level = level;
  +  }
  +
  +  @override
  +  visitField(Field node) {
  +    if (data.isFieldInitializerUsed(node)) {
  +      super.visitField(node);
  +    } else {
  +      var initializer = node.initializer;
  +      node.initializer = null;
  +      super.visitField(node);
  +      node.initializer = initializer;
  +    }
  +  }
  +
  +  @override
  +  visitFunctionNode(FunctionNode node) {
  +    var body = node.body;
  +    node.body = null;
  +    super.visitFunctionNode(node);
  +    node.body = body;
     }
   
     @override
  
positive.code: import 'package:kernel/core_types.dart';
  
  import '../problems.dart' show unimplemented, unsupported;
  
  /// Removes unnecessary libraries, classes, and members from [program].
  ///
  
negative.code:   void writeAdditionalExports(List<Reference> additionalExports) {
      super.writeAdditionalExports(
          insideIncludedLibrary ? additionalExports : const <Reference>[]);
    }
  
    @override
    void writeLibraries(Program program) {
      for (var library in program.libraries) {
        if (isIncluded(library.importUri) || data.isLibraryUsed(library)) {
          librariesToWrite.add(library);
        }
      }
      writeList(librariesToWrite, writeNode);
    }
  
    @override
  