/**
   * finish up the validation of a set of compiling defs.
   *
   * @param context only needed to do setCurrentNamspace.
   */
  private void finishValidation(AuraContext context, Collection<CompilingDef<?>> compiling)
      throws QuickFixException {
    //
    // Now validate our references.
    //
    for (CompilingDef<?> cd : compiling) {
      // FIXME: setting the current namespace on the context seems extremely hackish
      context.setCurrentNamespace(cd.descriptor.getNamespace());
      if (cd.built) {
        // FIXME: this may be incorrect, we may need to validate references even when we did
        // not actually build this, and we may not need to if the registry is pre-compiled.
        cd.def.validateReferences();
      }
    }

    //
    // And finally, mark everything as happily compiled.
    //
    for (CompilingDef<?> cd : compiling) {
      defs.put(cd.descriptor, cd.def);
      if (cd.built) {
        if (cd.cacheable) {
          defsCache.put(cd.descriptor, Optional.of(cd.def));
        }
        cd.def.markValid();
      }
    }
  }
  /**
   * Fill a compiling def for a descriptor.
   *
   * <p>This makes sure that we can get a registry for a given def, then tries to get the def from
   * the global cache, if that fails, it retrieves from the registry, and marks the def as locally
   * built.
   *
   * @param compiling the current compiling def (if there is one).
   * @throws QuickFixException if validateDefinition caused a quickfix.
   */
  private <D extends Definition> boolean fillCompilingDef(
      CompilingDef<D> compiling, AuraContext context) throws QuickFixException {
    assert compiling.def == null;
    {
      //
      // First, check our local cached defs to see if we have a fully compiled version.
      // in this case, we don't care about caching, since we are done.
      //
      @SuppressWarnings("unchecked")
      D localDef = (D) defs.get(compiling.descriptor);
      if (localDef != null) {
        compiling.def = localDef;
        compiling.built = !localDef.isValid();
        if (compiling.built) {
          localDef.validateDefinition();
        }
        return true;
      }
    }

    //
    // If there is no local cache, we must first check to see if there is a registry, as we may not
    // have
    // a registry (depending on configuration). In the case that we don't find one, we are done
    // here.
    //
    DefRegistry<D> registry = getRegistryFor(compiling.descriptor);
    if (registry == null) {
      defs.put(compiling.descriptor, null);
      return false;
    }

    //
    // Now, check if we can cache the def later, as we won't have the registry to check at a later
    // time.
    // If we can cache, look it up in the cache. If we find it, we have a built definition.
    //
    if (isCacheable(registry)) {
      compiling.cacheable = true;

      @SuppressWarnings("unchecked")
      Optional<D> opt = (Optional<D>) defsCache.getIfPresent(compiling.descriptor);
      if (opt != null) {
        D cachedDef = opt.orNull();

        if (cachedDef != null) {
          @SuppressWarnings("unchecked")
          DefDescriptor<D> canonical = (DefDescriptor<D>) cachedDef.getDescriptor();

          compiling.def = cachedDef;
          compiling.descriptor = canonical;
          compiling.built = false;
          defs.put(canonical, cachedDef);
          return true;
        } else {
          return false;
        }
      }
    }

    //
    // The last case. This is our first compile or the def is uncacheable.
    // In this case, we make sure that the initial validation is called, and put
    // the def in the non-validated set.
    //
    compiling.def = registry.getDef(compiling.descriptor);
    if (compiling.def == null) {
      return false;
    }
    @SuppressWarnings("unchecked")
    DefDescriptor<D> canonical = (DefDescriptor<D>) compiling.def.getDescriptor();
    compiling.descriptor = canonical;

    // cc.loggingService.incrementNum(LoggingService.DEF_COUNT);
    // FIXME: setting the current namespace on the context seems
    // extremely hackish
    context.setCurrentNamespace(canonical.getNamespace());
    compiling.def.validateDefinition();
    compiling.built = true;
    defs.put(canonical, compiling.def);
    return true;
  }