Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CandidateFinder.cpp

    r64727bd r251ce80  
    3838#include "typeops.h"              // for combos
    3939#include "Unify.h"
    40 #include "WidenMode.h"
    4140#include "AST/Expr.hpp"
    4241#include "AST/Node.hpp"
     
    750749                        // attempt to narrow based on expected target type
    751750                        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;
    767756                        }
    768757                }
     
    782771                                for (size_t i=0; i<nParams; ++i) {
    783772                                        auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    784                                         if ( !instantiateArgument( location,
     773                                        if (!instantiateArgument( location,
    785774                                                funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    786775                                }
     
    792781                        // matches
    793782                        // no default args for indirect calls
    794                         if ( !instantiateArgument( location,
     783                        if ( ! instantiateArgument( location,
    795784                                param, nullptr, args, results, genStart, symtab ) ) return;
    796785                }
     
    885874
    886875                if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    887                         addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" );
     876                        addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
    888877                } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    889                         addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
     878                        addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
    890879                }
    891880        }
     
    10181007                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    10191008                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    1020                                                 // if (!selfFinder.allowVoid && function->returns.empty()) continue;
    10211009                                                CandidateRef newFunc{ new Candidate{ *func } };
    10221010                                                newFunc->expr =
     
    10301018                                        if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    10311019                                                if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    1032                                                         CandidateRef newFunc( new Candidate( *func ) );
     1020                                                        CandidateRef newFunc{ new Candidate{ *func } };
    10331021                                                        newFunc->expr =
    10341022                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     
    10721060                if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    10731061
    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 
    10791062                // Compute conversion costs
    10801063                for ( CandidateRef & withFunc : found ) {
     
    10991082                        if ( cvtCost != Cost::infinity ) {
    11001083                                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                }
    11181087                found = std::move( candidates );
    11191088
    11201089                // 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 );
    11231092
    11241093                // function may return a struct/union value, in which case we need to add candidates
    11251094                // for implicit conversions to each of the anonymous members, which must happen after
    11261095                // `findMinCost`, since anon conversions are never the cheapest
    1127                 for ( const CandidateRef & c : found ) {
     1096                for ( const CandidateRef & c : winners ) {
    11281097                        addAnonConversions( c );
    11291098                }
    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() ) {
    11341102                        // If resolution is unsuccessful with a target type, try again without, since it
    11351103                        // will sometimes succeed when it wouldn't with a target type binding.
     
    11721140
    11731141                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                 }
    11841142                finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    11851143
     
    11871145
    11881146                CandidateList matches;
    1189                 Cost minExprCost = Cost::infinity;
    1190                 Cost minCastCost = Cost::infinity;
    11911147                for ( CandidateRef & cand : finder.candidates ) {
    11921148                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    12201176                                // count one safe conversion for each value that is thrown away
    12211177                                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 );
    12491190        }
    12501191
     
    15121453                // candidates for true result
    15131454                CandidateFinder finder2( context, tenv );
    1514                 finder2.allowVoid = true;
    15151455                finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    15161456                if ( finder2.candidates.empty() ) return;
     
    15181458                // candidates for false result
    15191459                CandidateFinder finder3( context, tenv );
    1520                 finder3.allowVoid = true;
    15211460                finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    15221461                if ( finder3.candidates.empty() ) return;
     
    15851524        void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) {
    15861525                CandidateFinder finder( context, tenv );
    1587                 finder.allowVoid = true;
    15881526                finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    15891527                for ( CandidateRef & r : finder.candidates ) {
     
    17021640                        CandidateFinder finder( context, tenv, toType );
    17031641                        finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    1704 
    1705                         Cost minExprCost = Cost::infinity;
    1706                         Cost minCastCost = Cost::infinity;
    17071642                        for ( CandidateRef & cand : finder.candidates ) {
    17081643                                if (reason.code == NotFound) reason.code = NoMatch;
     
    17421677                                        // count one safe conversion for each value that is thrown away
    17431678                                        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 );
    17621685                                }
    17631686                        }
     
    17651688
    17661689                // 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 );
    17711693        }
    17721694
     
    18341756                        auto found = selected.find( mangleName );
    18351757                        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 ) {
    18421759                                        PRINT(
    18431760                                                std::cerr << "cost " << newCand->cost << " beats "
     
    18461763
    18471764                                        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 ) {
    18491766                                        // if one of the candidates contains a deleted identifier, can pick the other,
    18501767                                        // since deleted expressions should not be ambiguous if there is another option
     
    19371854        */
    19381855
    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 ) {
    19411857                // trim candidates to single best one
    19421858                PRINT(
Note: See TracChangeset for help on using the changeset viewer.