'Find virtual packages in this spec, replace them with providers,
and normalize again to include the provider\'s (potentially virtual)
dependencies.  Repeat until there are no virtual deps.
Precondition: spec is normalized.
.. todo::
If a provider depends on something that conflicts with
other dependencies in the spec being expanded, this can
produce a conflicting spec.  For example, if mpich depends
on hwloc@:1.3 but something in the spec needs hwloc1.4:,
then we should choose an MPI other than mpich.  Cases like
this are infrequent, but should implement this before it is
a problem.'

def _expand_virtual_packages(self):

    self_index = ProviderIndex(self.traverse(), restrict=True)
    changed = False
    done = False
    while (not done):
        done = True
        for spec in list(self.traverse()):
            replacement = None
            if spec.external:
                continue
            if spec.virtual:
                replacement = self._find_provider(spec, self_index)
                if replacement:
                    spec._replace_with(replacement)
                    done = False
                    break
            if (not replacement):
                candidates = spack.concretizer.choose_virtual_or_external(spec)
                for replacement in candidates:
                    if (replacement is spec):
                        break
                    copy = self.copy()
                    copy[spec.name]._dup(replacement, deps=False)
                    try:
                        copy.normalize(force=True)
                        break
                    except SpecError:
                        continue
            if replacement.external:
                if spec._dependencies:
                    changed = True
                    spec._dependencies = DependencyMap(spec)
                replacement._dependencies = DependencyMap(replacement)
                replacement.architecture = self.architecture
            def feq(cfield, sfield):
                return ((not cfield) or (cfield == sfield))
            if ((replacement is spec) or (feq(replacement.name, spec.name) and feq(replacement.versions, spec.versions) and feq(replacement.compiler, spec.compiler) and feq(replacement.architecture, spec.architecture) and feq(replacement._dependencies, spec._dependencies) and feq(replacement.variants, spec.variants) and feq(replacement.external_path, spec.external_path) and feq(replacement.external_module, spec.external_module))):
                continue
            if spec.virtual:
                spec._replace_with(replacement)
                changed = True
            if spec._dup(replacement, deps=False, cleardeps=False):
                changed = True
            spec._dependencies.owner = spec
            self_index.update(spec)
            done = False
            break
    return changed
