Goose  Artifact [edcdb9a215]

Artifact edcdb9a2150e93c17b9ba237231e6a8c4c92ccd328709fb38a64d309aadbbb18:

  • File bs/builtins/types/func/invoke.cpp — part of check-in [bf81e30984] at 2021-09-18 17:00:20 on branch trunk —
    • Refactored LocationId into a separate class and actually use it everywhere instead of uint32_t, this makes it easier to make generic wrappers for APIs
    • g0 api: more work on the CIR api
    (user: achavasse size: 5115)

#include "builtins/builtins.h"

using namespace goose::sema;

namespace goose::builtins
{
    class FunctionInvocationRule : public InvocationRule
    {
        public:
            Value resolveInvocation( const Context& c, LocationId loc, const Value& callee, const Term& args ) const final
            {
                optional< TypeCheckingContext > bestTCC;
                optional< Term > bestSol;

                auto sig = GetFuncSig( callee );
                auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );

                auto us = FindBestTyping( sig, callPat, c );

                if( holds_alternative< NoUnification >( us ) )
                {
                    // TODO display details
                    DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                        "function arguments mismatch." );
                    return PoisonValue();
                }

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

                auto&& [s,tcc] = get< TCSol >( us );

                return invoke( c, loc, callee, args, s, tcc );
            }

            Value invoke( const Context& c, LocationId loc, const Value& callee, const Term& args, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
            {
                auto preparedCallee = prepareFunc( c, 0, callee, typeCheckedCallPat, tcc );
                if( preparedCallee.isPoison() )
                    return PoisonValue();

                auto callDecomp = Decompose( typeCheckedCallPat,
                    Val< pvec >()
                );

                const auto& typeCheckedRType = callDecomp->get()->terms().front();
                auto typeCheckedArgs = DropVectorTerm( typeCheckedCallPat, 1 );

                preparedCallee.setLocationId( loc );

                if( IsBuiltinFunc( preparedCallee ) )
                    return BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( typeCheckedArgs ) ) );

                if( IsBuiltinIntrinsicFunc( preparedCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( preparedCallee )( c, move( typeCheckedArgs ) );

                auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );

                if( ft.intrinsic() )
                {
                    // Intrinsic call: we insert the code builder wrapper as first param,
                    // wrap all args with TypeWrapper< Value >, and execute the function directly.
                    auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
                    if( !argList )
                        return PoisonValue();

                    execute::VM vm;
                    auto result = vm.execute( cir::Call( preparedCallee, move( *argList ) ) );
                    if( ft.returnType() == GetValueType< void >() )
                        return Value( GetValueType< void >(), 0U );

                    if( !result )
                        return PoisonValue();

                    // Unwrap the returned value
                    auto unwrapped = FromValue< TypeWrapper< Value > >( *result );
                    return unwrapped ? *unwrapped : PoisonValue();
                }

                auto argList = BuildArgListForCall( c, ft, typeCheckedArgs );
                if( !argList )
                    return PoisonValue();

                return BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( *argList ) ) );
            }

            optional< Term > getSignature( const Value& callee ) const final
            {
                return GetFuncSig( callee );
            }

            Value prepareFunc( const Context& c, LocationId funcValLocation, const Value& callee, const Term& typeCheckedCallPat, TypeCheckingContext& tcc ) const final
            {
                if( IsBuiltinFunc( callee ) || IsBuiltinIntrinsicFunc( callee ) )
                    return callee;

                // TODO better description with the function's name if possible (we may need to explicitely store it in the func)
                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                return CompileFunc( c, callee );
            }
    };

    ptr< InvocationRule >& GetFuncInvocationRule()
    {
        static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
        return pRule;
    }

    void SetupFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( ValuePattern( ANYTERM( _ ),

                ValueToEIR( Value( TypeType(), VEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
                ANYTERM( _ ), ANYTERM( _ ) ) ) ),

                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}