Goose  Artifact [194ccb41b2]

Artifact 194ccb41b22d2e95e324b1ae51585acd9845042fd7cc8a8523dc1d9d688373fc:

  • File bs/builtins/types/overloadset/invoke.cpp — part of check-in [0b47976c86] at 2021-09-23 21:32:13 on branch failed-ovl-resolution-optim-attempt — An attempt at optimizing overload resolution which works but provides no gain, archived in case some of the code might end up being useful some day (user: achavasse size: 4555)

#include "builtins/builtins.h"

//#define OVL_TC_DEBUG

using namespace goose::sema;

namespace goose::builtins
{
    class OverloadSetInvocationRule : public InvocationRule
    {
        public:
            Value resolveInvocation( const Context& c, LocationId loc, const Value& callee, const Term& args ) const final
            {
                const OverloadSet::Overload* bestOvl = nullptr;
                optional< TypeCheckingContext > bestTCC;
                optional< Term > bestSol;
                auto pOvlSet = *FromValue< ptr< OverloadSet > >( callee );

                #if TRACY_ENABLE
                    stringstream sstr;
                    sstr << pOvlSet->identity();
                #endif

                {
                    ProfileZoneScopedN( "Overload resolution" );
                    ProfileZoneName( sstr.str().c_str(), sstr.str().size() );

                    bool ambiguous = false;

                #if defined( OVL_TC_DEBUG ) && !defined( NDEBUG )
                    cout << "#### Invoking " << pOvlSet->identity() << endl;
                #endif

                    auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );
                    TypeCheckingContext tcc( c );
                    for( auto&& [s,ovl,tcc] : pOvlSet->typeCheck( callPat, tcc ) )
                    {
                        if( tcc.numUnknownValues() )
                            continue;

                        auto subs = Substitute( s, tcc );

                        // Typechecking rules often end up stripping part of the original type,
                        // and we want to invoke the overload where these removals are minimized.
                        //
                        // Obvious example: if there is an overload that accepts a reference
                        // and one that accepts a value of the same type and we started with a
                        // reference, then we want to call the overload where the typechecking
                        // solution didn't strip the reference.
                        //
                        // So we add the weight of the original arguments to the cost,
                        // and remove the cost of the typechecking solution to account for that.
                        int32_t cost = tcc.cost();
                        cost += GetWeight( callPat );
                        cost -= GetWeight( subs );
                        tcc.setCost( cost );

                        auto score = tcc.score();
                        if( bestTCC && score < bestTCC->score() )
                            continue;

                        auto pps = Postprocess( subs, tcc );
                        if( !pps )
                            continue;

                        if( bestTCC && score == bestTCC->score() )
                        {
                            ambiguous = true;
                            continue;
                        }

                        bestTCC = tcc;
                        bestSol = move( *pps );
                        bestOvl = ovl.get();
                        ambiguous = false;
                    }

                    if( ambiguous )
                    {
                        // TODO display details
                        DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                            "ambiguous function call." );
                        return PoisonValue();
                    }

                    if( !bestSol )
                    {
                        // TODO display details
                        DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                            "function arguments mismatch." );
                        return PoisonValue();
                    }

                #if defined( OVL_TC_DEBUG ) && !defined( NDEBUG )
                    bestTCC->DumpParamsTraces( cout );
                    cout << endl;
                #endif
                }

                return bestOvl->pInvRule->invoke( c, loc, bestOvl->callee, args, *bestSol, *bestTCC );
            }
    };

    ptr< InvocationRule >& GetOverloadSetInvocationRule()
    {
        static ptr< InvocationRule > pRule = make_shared< OverloadSetInvocationRule >();
        return pRule;
    }

    void SetupOverloadSetInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( Value(
                GetValueType< ptr< OverloadSet > >(),
                ANYTERM( _ ) ) ),
            GetOverloadSetInvocationRule() );
    }
}