def resolve_for needed, specs
states = []
while !needed.empty?
@stats.iteration!
dep = needed.remove
explain :try, [dep, dep.requester ? dep.requester.request : :toplevel]
explain_list(:next5) { needed.next5 }
explain_list(:specs) { Array(specs).map { |x| x.full_name }.sort }
if specs && existing = specs.find { |s| dep.name == s.name }
next if dep.matches_spec? existing
conflict = handle_conflict dep, existing
return conflict unless dep.requester
explain :conflict, dep, :existing, existing.full_name
depreq = dep.requester.request
state = nil
until states.empty?
x = states.pop
i = existing.request.requester
explain :consider, x.spec.full_name, [depreq.name, dep.name, i ? i.name : :top]
if x.spec.name == depreq.name or
x.spec.name == dep.name or
(i && (i.name == x.spec.name))
explain :found, x.spec.full_name
state = x
break
end
end
return conflict unless state
@stats.backtracking!
needed, specs = resolve_for_conflict needed, specs, state
states << state unless state.possibles.empty?
next
end
matching, all = find_possible dep
case matching.size
when 0
resolve_for_zero dep, all
when 1
needed, specs =
resolve_for_single needed, specs, dep, matching
else
needed, specs =
resolve_for_multiple needed, specs, states, dep, matching
end
end
specs
end