Goose  Artifact [f67ab9b9b0]

Artifact f67ab9b9b0683092a19ab586aa4762662aa59163950f3117e56adb6b41aa295d:

  • File bs/builtins/types/template/tc-tdecl.cpp — part of check-in [0db147f117] at 2024-09-15 20:24:31 on branch cir-ssa-refactor — Add clang format settings, reformat everything (user: achavasse size: 7432)

#include "builtins/builtins.h"

namespace goose::builtins
{
    Term BuildArgPatternFromTDecl( const Context& c, Term&& sig )
    {
        return ValueToEIR( ValuePattern( HOLE( "_"_sid ), move( sig ), HOLE( "_"_sid ) ) );
    }

    void SetupTDeclTypeChecking( Env& e )
    {
        auto tDeclPat = TDeclSigPattern( ANYTERM( _ ), Hole::Behavior::Any, ANYTERM( _ ) );

        e.typeCheckingRuleSet()->addHalfUnificationRule( tDeclPat,
            []( const Term& lhs, TypeCheckingContext& c )
            {
                auto [name, bhv, sig] = DecomposeTDSig( lhs );
                return HalfUnify( sig, c );
            } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( tDeclPat, ANYTERM( _ ),
            []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
            {
                auto [name, bhv, typeSig] = DecomposeTDSig( lhs );
                auto tdeclHole = HOLE( DecorateTVarName( name ), ""_sid, bhv );

                auto pat = ValueToEIR( Value( move( typeSig ), HOLE( "_"_sid ) ) );
                for( auto&& [s, tcc] : TypeCheck( pat, rhs, tcc ) )
                {
                    // We need to typecheck the result with a hole named after the decl. However,
                    // since both sides of this unification orignally appeared on the LHS, we need
                    // to setup RHS to alias the LHS namespace for this.
                    auto savedRHSSubContext = tcc.RHSSubContext();
                    tcc.RHSSubContext() = tcc.LHSSubContext();

                    for( auto&& [s, tcc] : TypeCheck( s, tdeclHole, tcc ) )
                    {
                        tcc.RHSSubContext() = savedRHSSubContext;
                        co_yield { s, tcc };
                    }
                }
            } );

        e.typeCheckingRuleSet()->addUnificationRule( tDeclPat, ANYTERM( _ ),
            []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
            {
                auto [name, bhv, typeSig] = DecomposeTDSig( lhs );
                auto tdeclHole = HOLE( DecorateTVarName( name ), ""_sid, bhv );

                auto pat = ValueToEIR( Value( move( typeSig ), HOLE( "_"_sid ) ) );
                for( auto&& [s, tcc] : Unify( pat, rhs, tcc ) )
                {
                    // We need to unify the result with a hole named after the decl. However, since
                    // both sides of this unification orignally appeared on the LHS, we need to
                    // setup RHS to alias the LHS namespace for this.
                    auto savedRHSSubContext = tcc.RHSSubContext();
                    tcc.RHSSubContext() = tcc.LHSSubContext();

                    for( auto&& [s, tcc] : Unify( s, tdeclHole, tcc ) )
                    {
                        tcc.RHSSubContext() = savedRHSSubContext;
                        co_yield { s, tcc };
                    }
                }
            } );

        // tfunc tdecl param / tfunc arg
        auto tDeclTFuncPat = TDeclSigPattern(
            ANYTERM( _ ), Hole::Behavior::Any, TFuncTypeSigPattern( ANYTERM( _ ), ANYTERM( _ ) ) );

        e.typeCheckingRuleSet()->addTypeCheckingRule(

            tDeclTFuncPat,

            ValueToEIR( ValuePattern( TSID( constant ), TFuncTypePattern(), ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
            {
                auto [name, bhv, typeSig] = DecomposeTDSig( lhs );
                auto [_, tfSig] = DecomposeTFTSig( typeSig );

                auto callPat = BuildArgPatternFromTDecl( tcc.context(), move( typeSig ) );
                auto tdeclHole = HOLE( DecorateTVarName( name ), ""_sid, bhv );

                auto rhsVal = *EIRToValue( rhs );

                ConstrainedFunc cfunc( tfSig, GetTFuncInvocationRule(), rhsVal );
                auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );

                // Create a new named hole namespace to isolate holes from the passed function from
                // those in the called function.
                auto savedRHSSubContext = tcc.RHSSubContext();
                tcc.RHSSubContext().namespaceIndex = tcc.newNamespaceIndex();

                auto oldValueRequired = tcc.isValueResolutionRequired();
                tcc.setValueResolutionRequired( false );

                for( auto&& [s, tcc] : TypeCheck( callPat, rhs, tcc ) )
                {
                    // Restore the namespace
                    tcc.RHSSubContext() = savedRHSSubContext;
                    tcc.setValueResolutionRequired( oldValueRequired );

                    // We need to unify the result with a hole named after the decl. However, since
                    // both sides of this unification orignally appeared on the LHS, we need to
                    // setup RHS to alias the LHS namespace for this.
                    tcc.RHSSubContext() = tcc.LHSSubContext();

                    for( auto&& [s, tcc] : Unify( cFuncTerm, tdeclHole, tcc ) )
                    {
                        tcc.RHSSubContext() = savedRHSSubContext;
                        co_yield { s, tcc };
                    }
                }
            } );

        // tfunc tdecl param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule(

            move( tDeclTFuncPat ),

            ValueToEIR( ValuePattern(
                TSID( constant ), GetValueType< ptr< sema::OverloadSet > >(), ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
            {
                auto [name, bhv, typeSig] = DecomposeTDSig( lhs );
                auto [_, tfSig] = DecomposeTFTSig( typeSig );

                auto callPat = BuildArgPatternFromTDecl( tcc.context(), move( typeSig ) );
                auto tdeclHole = HOLE( DecorateTVarName( name ), ""_sid, bhv );

                auto rhsVal = *EIRToValue( rhs );

                ConstrainedFunc cfunc( tfSig, GetOverloadSetInvocationRule(), rhsVal );
                auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );

                // Create a new named hole namespace to isolate holes from the passed function from
                // those in the called function.
                auto savedRHSSubContext = tcc.RHSSubContext();
                tcc.RHSSubContext().namespaceIndex = tcc.newNamespaceIndex();

                auto oldValueRequired = tcc.isValueResolutionRequired();
                tcc.setValueResolutionRequired( false );

                for( auto&& [s, tcc] : TypeCheck( callPat, rhs, tcc ) )
                {
                    // Restore the namespace
                    tcc.RHSSubContext() = savedRHSSubContext;
                    tcc.setValueResolutionRequired( oldValueRequired );

                    // We need to unify the result with a hole named after the decl. However, since
                    // both sides of this unification orignally appeared on the LHS, we need to
                    // setup RHS to alias the LHS namespace for this.
                    tcc.RHSSubContext() = tcc.LHSSubContext();

                    for( auto&& [s, tcc] : Unify( cFuncTerm, tdeclHole, tcc ) )
                    {
                        tcc.RHSSubContext() = savedRHSSubContext;
                        co_yield { s, tcc };
                    }
                }
            } );
    }
} // namespace goose::builtins