- File:
-
- 1 edited
-
src/ResolvExpr/CandidateFinder.cpp (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
r1389810 r0292aa4 1595 1595 // unification run for side-effects 1596 1596 bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab ); 1597 (void) canUnify;1597 (void) canUnify; 1598 1598 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1599 1599 symtab, env ); … … 1645 1645 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1646 1646 /// return type. Skips ambiguous candidates. 1647 1648 } // anonymous namespace 1649 1650 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1651 struct PruneStruct { 1652 CandidateRef candidate; 1653 bool ambiguous; 1654 1655 PruneStruct() = default; 1656 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1657 }; 1658 1659 // find lowest-cost candidate for each type 1660 std::unordered_map< std::string, PruneStruct > selected; 1661 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1662 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1663 for ( CandidateRef & candidate : candidates ) { 1664 std::string mangleName; 1665 { 1666 ast::ptr< ast::Type > newType = candidate->expr->result; 1667 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1668 candidate->env.apply( newType ); 1669 mangleName = Mangle::mangle( newType ); 1670 } 1671 1672 auto found = selected.find( mangleName ); 1673 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1674 PRINT( 1675 std::cerr << "cost " << candidate->cost << " loses to " 1676 << found->second.candidate->cost << std::endl; 1677 ) 1678 continue; 1679 } 1680 1681 // xxx - when do satisfyAssertions produce more than 1 result? 1682 // this should only happen when initial result type contains 1683 // unbound type parameters, then it should never be pruned by 1684 // the previous step, since renameTyVars guarantees the mangled name 1685 // is unique. 1686 CandidateList satisfied; 1687 satisfyAssertions(candidate, localSyms, satisfied, errors); 1688 1689 for (auto & newCand : satisfied) { 1690 // recomputes type key, if satisfyAssertions changed it 1647 CandidateList pruneCandidates( CandidateList & candidates ) { 1648 struct PruneStruct { 1649 CandidateRef candidate; 1650 bool ambiguous; 1651 1652 PruneStruct() = default; 1653 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1654 }; 1655 1656 // find lowest-cost candidate for each type 1657 std::unordered_map< std::string, PruneStruct > selected; 1658 for ( CandidateRef & candidate : candidates ) { 1659 std::string mangleName; 1691 1660 { 1692 ast::ptr< ast::Type > newType = newCand->expr->result;1693 assertf( newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());1694 newCand->env.apply( newType );1661 ast::ptr< ast::Type > newType = candidate->expr->result; 1662 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1663 candidate->env.apply( newType ); 1695 1664 mangleName = Mangle::mangle( newType ); 1696 1665 } 1666 1697 1667 auto found = selected.find( mangleName ); 1698 1668 if ( found != selected.end() ) { 1699 if ( newCand->cost < found->second.candidate->cost ) {1669 if ( candidate->cost < found->second.candidate->cost ) { 1700 1670 PRINT( 1701 std::cerr << "cost " << newCand->cost << " beats "1671 std::cerr << "cost " << candidate->cost << " beats " 1702 1672 << found->second.candidate->cost << std::endl; 1703 1673 ) 1704 1674 1705 found->second = PruneStruct{ newCand};1706 } else if ( newCand->cost == found->second.candidate->cost ) {1675 found->second = PruneStruct{ candidate }; 1676 } else if ( candidate->cost == found->second.candidate->cost ) { 1707 1677 // if one of the candidates contains a deleted identifier, can pick the other, 1708 1678 // since deleted expressions should not be ambiguous if there is another option 1709 1679 // that is at least as good 1710 if ( findDeletedExpr( newCand->expr ) ) {1680 if ( findDeletedExpr( candidate->expr ) ) { 1711 1681 // do nothing 1712 1682 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1713 1683 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1714 1684 PRINT( std::cerr << "current is deleted" << std::endl; ) 1715 found->second = PruneStruct{ newCand};1685 found->second = PruneStruct{ candidate }; 1716 1686 } else { 1717 1687 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1718 1688 found->second.ambiguous = true; 1719 1689 } 1720 } else { 1721 // xxx - can satisfyAssertions increase the cost? 1690 } else { 1722 1691 PRINT( 1723 std::cerr << "cost " << newCand->cost << " loses to "1692 std::cerr << "cost " << candidate->cost << " loses to " 1724 1693 << found->second.candidate->cost << std::endl; 1725 ) 1694 ) 1726 1695 } 1727 1696 } else { 1728 selected.emplace_hint( found, mangleName, newCand ); 1729 } 1730 } 1697 selected.emplace_hint( found, mangleName, candidate ); 1698 } 1699 } 1700 1701 // report unambiguous min-cost candidates 1702 CandidateList out; 1703 for ( auto & target : selected ) { 1704 if ( target.second.ambiguous ) continue; 1705 1706 CandidateRef cand = target.second.candidate; 1707 1708 ast::ptr< ast::Type > newResult = cand->expr->result; 1709 cand->env.applyFree( newResult ); 1710 cand->expr = ast::mutate_field( 1711 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1712 1713 out.emplace_back( cand ); 1714 } 1715 return out; 1731 1716 } 1732 1717 1733 // report unambiguous min-cost candidates 1734 // CandidateList out; 1735 for ( auto & target : selected ) { 1736 if ( target.second.ambiguous ) continue; 1737 1738 CandidateRef cand = target.second.candidate; 1739 1740 ast::ptr< ast::Type > newResult = cand->expr->result; 1741 cand->env.applyFree( newResult ); 1742 cand->expr = ast::mutate_field( 1743 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1744 1745 out.emplace_back( cand ); 1746 } 1747 // if everything is lost in satisfyAssertions, report the error 1748 return !selected.empty(); 1749 } 1718 } // anonymous namespace 1750 1719 1751 1720 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { … … 1770 1739 } 1771 1740 1772 /*1773 1741 if ( mode.satisfyAssns || mode.prune ) { 1774 1742 // trim candidates to just those where the assertions are satisfiable … … 1793 1761 candidates = move( satisfied ); 1794 1762 } 1795 */1796 1763 1797 1764 if ( mode.prune ) { … … 1802 1769 ) 1803 1770 1804 CandidateList pruned; 1805 std::vector<std::string> errors; 1806 bool found = pruneCandidates( candidates, pruned, errors ); 1771 CandidateList pruned = pruneCandidates( candidates ); 1807 1772 1808 1773 if ( mode.failFast && pruned.empty() ) { 1809 1774 std::ostringstream stream; 1810 if (found) { 1811 CandidateList winners = findMinCost( candidates ); 1812 stream << "Cannot choose between " << winners.size() << " alternatives for " 1813 "expression\n"; 1814 ast::print( stream, expr ); 1815 stream << " Alternatives are:\n"; 1816 print( stream, winners, 1 ); 1817 SemanticError( expr->location, stream.str() ); 1818 } 1819 else { 1820 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1821 for ( const auto& err : errors ) { 1822 stream << err; 1823 } 1824 SemanticError( expr->location, stream.str() ); 1825 } 1775 CandidateList winners = findMinCost( candidates ); 1776 stream << "Cannot choose between " << winners.size() << " alternatives for " 1777 "expression\n"; 1778 ast::print( stream, expr ); 1779 stream << " Alternatives are:\n"; 1780 print( stream, winners, 1 ); 1781 SemanticError( expr->location, stream.str() ); 1826 1782 } 1827 1783
Note:
See TracChangeset
for help on using the changeset viewer.