Changeset c84dd61 for src/ResolvExpr/CandidateFinder.cpp
- Timestamp:
- Jun 21, 2023, 2:38:55 AM (2 years ago)
- Branches:
- master
- Children:
- 92355883
- Parents:
- 0b0a285 (diff), 2de175ce (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/CandidateFinder.cpp
r0b0a285 rc84dd61 38 38 #include "typeops.h" // for combos 39 39 #include "Unify.h" 40 #include "WidenMode.h" 40 41 #include "AST/Expr.hpp" 41 42 #include "AST/Node.hpp" … … 749 750 // attempt to narrow based on expected target type 750 751 const ast::Type * returnType = funcType->returns.front(); 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 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 } 756 767 } 757 768 } … … 771 782 for (size_t i=0; i<nParams; ++i) { 772 783 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 773 if ( !instantiateArgument( location,784 if ( !instantiateArgument( location, 774 785 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 775 786 } … … 781 792 // matches 782 793 // no default args for indirect calls 783 if ( ! 794 if ( !instantiateArgument( location, 784 795 param, nullptr, args, results, genStart, symtab ) ) return; 785 796 } … … 874 885 875 886 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 876 addAggMembers( structInst, aggrExpr, *cand, Cost:: safe, "" );887 addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" ); 877 888 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 878 addAggMembers( unionInst, aggrExpr, *cand, Cost:: safe, "" );889 addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" ); 879 890 } 880 891 } … … 1007 1018 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1008 1019 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1020 // if (!selfFinder.allowVoid && function->returns.empty()) continue; 1009 1021 CandidateRef newFunc{ new Candidate{ *func } }; 1010 1022 newFunc->expr = … … 1018 1030 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1019 1031 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1020 CandidateRef newFunc { new Candidate{ *func } };1032 CandidateRef newFunc( new Candidate( *func ) ); 1021 1033 newFunc->expr = 1022 1034 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); … … 1060 1072 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1061 1073 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 1062 1079 // Compute conversion costs 1063 1080 for ( CandidateRef & withFunc : found ) { … … 1082 1099 if ( cvtCost != Cost::infinity ) { 1083 1100 withFunc->cvtCost = cvtCost; 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 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 ); 1087 1118 found = std::move( candidates ); 1088 1119 1089 1120 // use a new list so that candidates are not examined by addAnonConversions twice 1090 CandidateList winners = findMinCost( found );1091 promoteCvtCost( winners );1121 // CandidateList winners = findMinCost( found ); 1122 // promoteCvtCost( winners ); 1092 1123 1093 1124 // function may return a struct/union value, in which case we need to add candidates 1094 1125 // for implicit conversions to each of the anonymous members, which must happen after 1095 1126 // `findMinCost`, since anon conversions are never the cheapest 1096 for ( const CandidateRef & c : winners) {1127 for ( const CandidateRef & c : found ) { 1097 1128 addAnonConversions( c ); 1098 1129 } 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 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 ) { 1102 1134 // If resolution is unsuccessful with a target type, try again without, since it 1103 1135 // will sometimes succeed when it wouldn't with a target type binding. … … 1140 1172 1141 1173 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 } 1142 1184 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1143 1185 … … 1145 1187 1146 1188 CandidateList matches; 1189 Cost minExprCost = Cost::infinity; 1190 Cost minCastCost = Cost::infinity; 1147 1191 for ( CandidateRef & cand : finder.candidates ) { 1148 1192 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1176 1220 // count one safe conversion for each value that is thrown away 1177 1221 thisCost.incSafe( discardedValues ); 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 ); 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 ); 1190 1249 } 1191 1250 … … 1453 1512 // candidates for true result 1454 1513 CandidateFinder finder2( context, tenv ); 1514 finder2.allowVoid = true; 1455 1515 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1456 1516 if ( finder2.candidates.empty() ) return; … … 1458 1518 // candidates for false result 1459 1519 CandidateFinder finder3( context, tenv ); 1520 finder3.allowVoid = true; 1460 1521 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1461 1522 if ( finder3.candidates.empty() ) return; … … 1524 1585 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1525 1586 CandidateFinder finder( context, tenv ); 1587 finder.allowVoid = true; 1526 1588 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1527 1589 for ( CandidateRef & r : finder.candidates ) { … … 1640 1702 CandidateFinder finder( context, tenv, toType ); 1641 1703 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1704 1705 Cost minExprCost = Cost::infinity; 1706 Cost minCastCost = Cost::infinity; 1642 1707 for ( CandidateRef & cand : finder.candidates ) { 1643 1708 if (reason.code == NotFound) reason.code = NoMatch; … … 1677 1742 // count one safe conversion for each value that is thrown away 1678 1743 thisCost.incSafe( discardedValues ); 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 ); 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 } 1685 1762 } 1686 1763 } … … 1688 1765 1689 1766 // select first on argument cost, then conversion cost 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1767 // CandidateList minArgCost = findMinCost( matches ); 1768 // promoteCvtCost( minArgCost ); 1769 // candidates = findMinCost( minArgCost ); 1770 candidates = std::move(matches); 1693 1771 } 1694 1772 … … 1756 1834 auto found = selected.find( mangleName ); 1757 1835 if ( found != selected.end() ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 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) ) { 1759 1842 PRINT( 1760 1843 std::cerr << "cost " << newCand->cost << " beats " … … 1763 1846 1764 1847 found->second = PruneStruct{ newCand }; 1765 } else if ( newCand->cost == found->second.candidate->cost ) {1848 } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost ) { 1766 1849 // if one of the candidates contains a deleted identifier, can pick the other, 1767 1850 // since deleted expressions should not be ambiguous if there is another option … … 1854 1937 */ 1855 1938 1856 if ( mode.prune ) { 1939 // optimization: don't prune for NameExpr since it never has cost 1940 if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr) ) { 1857 1941 // trim candidates to single best one 1858 1942 PRINT(
Note:
See TracChangeset
for help on using the changeset viewer.