- File:
-
- 1 edited
-
src/ResolvExpr/CandidateFinder.cpp (modified) (21 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
r64727bd r251ce80 38 38 #include "typeops.h" // for combos 39 39 #include "Unify.h" 40 #include "WidenMode.h"41 40 #include "AST/Expr.hpp" 42 41 #include "AST/Node.hpp" … … 750 749 // attempt to narrow based on expected target type 751 750 const ast::Type * returnType = funcType->returns.front(); 752 if ( selfFinder.strictMode ) { 753 if ( ! unifyExact( 754 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct? 755 ) { 756 // unification failed, do not pursue this candidate 757 return; 758 } 759 } 760 else { 761 if ( ! unify( 762 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 763 ) { 764 // unification failed, do not pursue this candidate 765 return; 766 } 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 767 756 } 768 757 } … … 782 771 for (size_t i=0; i<nParams; ++i) { 783 772 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 784 if ( !instantiateArgument( location,773 if (!instantiateArgument( location, 785 774 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 786 775 } … … 792 781 // matches 793 782 // no default args for indirect calls 794 if ( ! instantiateArgument( location,783 if ( ! instantiateArgument( location, 795 784 param, nullptr, args, results, genStart, symtab ) ) return; 796 785 } … … 885 874 886 875 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 887 addAggMembers( structInst, aggrExpr, *cand, Cost:: unsafe, "" );876 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" ); 888 877 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 889 addAggMembers( unionInst, aggrExpr, *cand, Cost:: unsafe, "" );878 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" ); 890 879 } 891 880 } … … 1018 1007 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1019 1008 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1020 // if (!selfFinder.allowVoid && function->returns.empty()) continue;1021 1009 CandidateRef newFunc{ new Candidate{ *func } }; 1022 1010 newFunc->expr = … … 1030 1018 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1031 1019 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1032 CandidateRef newFunc ( new Candidate( *func ) );1020 CandidateRef newFunc{ new Candidate{ *func } }; 1033 1021 newFunc->expr = 1034 1022 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); … … 1072 1060 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1073 1061 1074 // only keep the best matching intrinsic result to match C semantics (no unexpected narrowing/widening)1075 // TODO: keep one for each set of argument candidates?1076 Cost intrinsicCost = Cost::infinity;1077 CandidateList intrinsicResult;1078 1079 1062 // Compute conversion costs 1080 1063 for ( CandidateRef & withFunc : found ) { … … 1099 1082 if ( cvtCost != Cost::infinity ) { 1100 1083 withFunc->cvtCost = cvtCost; 1101 withFunc->cost += cvtCost; 1102 auto func = withFunc->expr.strict_as<ast::ApplicationExpr>()->func.as<ast::VariableExpr>(); 1103 if (func && func->var->linkage == ast::Linkage::Intrinsic) { 1104 if (withFunc->cost < intrinsicCost) { 1105 intrinsicResult.clear(); 1106 intrinsicCost = withFunc->cost; 1107 } 1108 if (withFunc->cost == intrinsicCost) { 1109 intrinsicResult.emplace_back(std::move(withFunc)); 1110 } 1111 } 1112 else { 1113 candidates.emplace_back( std::move( withFunc ) ); 1114 } 1115 } 1116 } 1117 spliceBegin( candidates, intrinsicResult ); 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 1118 1087 found = std::move( candidates ); 1119 1088 1120 1089 // use a new list so that candidates are not examined by addAnonConversions twice 1121 //CandidateList winners = findMinCost( found );1122 //promoteCvtCost( winners );1090 CandidateList winners = findMinCost( found ); 1091 promoteCvtCost( winners ); 1123 1092 1124 1093 // function may return a struct/union value, in which case we need to add candidates 1125 1094 // for implicit conversions to each of the anonymous members, which must happen after 1126 1095 // `findMinCost`, since anon conversions are never the cheapest 1127 for ( const CandidateRef & c : found) {1096 for ( const CandidateRef & c : winners ) { 1128 1097 addAnonConversions( c ); 1129 1098 } 1130 // would this be too slow when we don't check cost anymore? 1131 spliceBegin( candidates, found ); 1132 1133 if ( candidates.empty() && targetType && ! targetType->isVoid() && !selfFinder.strictMode ) { 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 1134 1102 // If resolution is unsuccessful with a target type, try again without, since it 1135 1103 // will sometimes succeed when it wouldn't with a target type binding. … … 1172 1140 1173 1141 CandidateFinder finder( context, tenv, toType ); 1174 if (toType->isVoid()) {1175 finder.allowVoid = true;1176 }1177 if ( castExpr->kind == ast::CastExpr::Return ) {1178 finder.strictMode = true;1179 finder.find( castExpr->arg, ResolvMode::withAdjustment() );1180 1181 // return casts are eliminated (merely selecting an overload, no actual operation)1182 candidates = std::move(finder.candidates);1183 }1184 1142 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1185 1143 … … 1187 1145 1188 1146 CandidateList matches; 1189 Cost minExprCost = Cost::infinity;1190 Cost minCastCost = Cost::infinity;1191 1147 for ( CandidateRef & cand : finder.candidates ) { 1192 1148 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1220 1176 // count one safe conversion for each value that is thrown away 1221 1177 thisCost.incSafe( discardedValues ); 1222 // select first on argument cost, then conversion cost 1223 if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) { 1224 minExprCost = cand->cost; 1225 minCastCost = thisCost; 1226 matches.clear(); 1227 1228 1229 } 1230 // ambiguous case, still output candidates to print in error message 1231 if ( cand->cost == minExprCost && thisCost == minCastCost ) { 1232 CandidateRef newCand = std::make_shared<Candidate>( 1233 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1234 copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost); 1235 // currently assertions are always resolved immediately so this should have no effect. 1236 // if this somehow changes in the future (e.g. delayed by indeterminate return type) 1237 // we may need to revisit the logic. 1238 inferParameters( newCand, matches ); 1239 } 1240 // else skip, better alternatives found 1241 1242 } 1243 } 1244 candidates = std::move(matches); 1245 1246 //CandidateList minArgCost = findMinCost( matches ); 1247 //promoteCvtCost( minArgCost ); 1248 //candidates = findMinCost( minArgCost ); 1178 CandidateRef newCand = std::make_shared<Candidate>( 1179 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1180 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1181 cand->cost + thisCost ); 1182 inferParameters( newCand, matches ); 1183 } 1184 } 1185 1186 // select first on argument cost, then conversion cost 1187 CandidateList minArgCost = findMinCost( matches ); 1188 promoteCvtCost( minArgCost ); 1189 candidates = findMinCost( minArgCost ); 1249 1190 } 1250 1191 … … 1512 1453 // candidates for true result 1513 1454 CandidateFinder finder2( context, tenv ); 1514 finder2.allowVoid = true;1515 1455 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1516 1456 if ( finder2.candidates.empty() ) return; … … 1518 1458 // candidates for false result 1519 1459 CandidateFinder finder3( context, tenv ); 1520 finder3.allowVoid = true;1521 1460 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1522 1461 if ( finder3.candidates.empty() ) return; … … 1585 1524 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1586 1525 CandidateFinder finder( context, tenv ); 1587 finder.allowVoid = true;1588 1526 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1589 1527 for ( CandidateRef & r : finder.candidates ) { … … 1702 1640 CandidateFinder finder( context, tenv, toType ); 1703 1641 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1704 1705 Cost minExprCost = Cost::infinity;1706 Cost minCastCost = Cost::infinity;1707 1642 for ( CandidateRef & cand : finder.candidates ) { 1708 1643 if (reason.code == NotFound) reason.code = NoMatch; … … 1742 1677 // count one safe conversion for each value that is thrown away 1743 1678 thisCost.incSafe( discardedValues ); 1744 if ( cand->cost < minExprCost || ( cand->cost == minExprCost && thisCost < minCastCost ) ) { 1745 minExprCost = cand->cost; 1746 minCastCost = thisCost; 1747 matches.clear(); 1748 } 1749 // ambiguous case, still output candidates to print in error message 1750 if ( cand->cost == minExprCost && thisCost == minCastCost ) { 1751 CandidateRef newCand = std::make_shared<Candidate>( 1752 new ast::InitExpr{ 1753 initExpr->location, 1754 restructureCast( cand->expr, toType ), 1755 initAlt.designation }, 1756 std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost ); 1757 // currently assertions are always resolved immediately so this should have no effect. 1758 // if this somehow changes in the future (e.g. delayed by indeterminate return type) 1759 // we may need to revisit the logic. 1760 inferParameters( newCand, matches ); 1761 } 1679 CandidateRef newCand = std::make_shared<Candidate>( 1680 new ast::InitExpr{ 1681 initExpr->location, restructureCast( cand->expr, toType ), 1682 initAlt.designation }, 1683 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1684 inferParameters( newCand, matches ); 1762 1685 } 1763 1686 } … … 1765 1688 1766 1689 // select first on argument cost, then conversion cost 1767 // CandidateList minArgCost = findMinCost( matches ); 1768 // promoteCvtCost( minArgCost ); 1769 // candidates = findMinCost( minArgCost ); 1770 candidates = std::move(matches); 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1771 1693 } 1772 1694 … … 1834 1756 auto found = selected.find( mangleName ); 1835 1757 if ( found != selected.end() ) { 1836 // tiebreaking by picking the lower cost on CURRENT expression 1837 // NOTE: this behavior is different from C semantics. 1838 // Specific remediations are performed for C operators at postvisit(UntypedExpr). 1839 // Further investigations may take place. 1840 if ( newCand->cost < found->second.candidate->cost 1841 || (newCand->cost == found->second.candidate->cost && newCand->cvtCost < found->second.candidate->cvtCost) ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 1842 1759 PRINT( 1843 1760 std::cerr << "cost " << newCand->cost << " beats " … … 1846 1763 1847 1764 found->second = PruneStruct{ newCand }; 1848 } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost) {1765 } else if ( newCand->cost == found->second.candidate->cost ) { 1849 1766 // if one of the candidates contains a deleted identifier, can pick the other, 1850 1767 // since deleted expressions should not be ambiguous if there is another option … … 1937 1854 */ 1938 1855 1939 // optimization: don't prune for NameExpr since it never has cost 1940 if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr) ) { 1856 if ( mode.prune ) { 1941 1857 // trim candidates to single best one 1942 1858 PRINT(
Note:
See TracChangeset
for help on using the changeset viewer.