docs: @Requires({
      "roots != null",
      "diagnosticManager != null"
    })
    @Ensures({
      "result != null",
      "result.size() >= roots.size()",
      "result.size() <= 2 * roots.size()"
    })
    protected List<TypeModel> createTypes(Set<TypeElement> roots,
                                          DiagnosticManager diagnosticManager) {
      boolean errors = false;
  
      /*
       * Extract all type names that will be part of this compilation
       * task.
       */
      final HashSet<String> knownTypeNames = new HashSet<String>();
      for (TypeElement r : roots) {
        ElementScanner6<Void, Void> visitor =
            new ElementScanner6<Void, Void>() {
              @Override
              public Void visitType(TypeElement e, Void p) {
                knownTypeNames.add(e.getQualifiedName().toString());
                return super.visitType(e, p);
              }
            };
        r.accept(visitor, null);
      }
      /*
       * Mark annotations inherited from classes compiled in the same
       * task as weak so we don't generate stubs for them later on. This
       * prevents name clashes due to erasure.
       */
      ArrayList<TypeModel> undecoratedTypes =
          new ArrayList<TypeModel>(roots.size());
      for (TypeElement r : roots) {
        TypeModel type = factory.createType(r, diagnosticManager);
        ElementScanner annotator =
            new ElementScanner() {
              @Override
              public void visitContractAnnotation(
                  ContractAnnotationModel annotation) {
                if (annotation.isVirtual()
                    && knownTypeNames.contains(
                        annotation.getOwner().getQualifiedName())) {
                  annotation.setWeakVirtual(true);
                }
              }
            };
        type.accept(annotator);
        undecoratedTypes.add(type);
      }
      /*
       * Decorate the type models with contract methods and create
       * helper types.
       */
      ArrayList<TypeModel> types =
          new ArrayList<TypeModel>(undecoratedTypes.size());
      for (TypeModel type : undecoratedTypes) {
        ClassContractCreator creator =
            new ClassContractCreator(diagnosticManager);
        type.accept(creator);
        TypeModel helper = creator.getHelperType();
        types.add(type);
        if (helper != null) {
          types.add(helper);
        }
      }
  
      return types;
    }