#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
namespace goose::builtins
{
void SetupFunctionTypeChecking( Env& e )
{
// Default param rule: we basically treat it like a regular value.
// Things that need a more specific rule for params can override this with
// more specific pattern.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( param ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *ValuePatternFromEIR( lhs );
lhsVal.sort() = HOLE( "_"_sid );
co_yield TypeCheck( ValueToEIR( lhsVal ), rhs, tcc );
} );
// Constant param rule
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lhsVal = *ValuePatternFromEIR( lhs );
auto rhsVal = *ValuePatternFromEIR( rhs );
// Check the types
for( auto&& [ut,tcc] : TypeCheck( lhsVal.type(), rhsVal.type(), tcc ) )
{
// Check the contents
for( auto&& [uv,tcc] : TypeCheck( lhsVal.val(), rhsVal.val(), tcc ) )
{
ValuePattern result( move( ut ), move( uv ), rhsVal.locationId() );
co_yield { ValueToEIR( move( result ) ), tcc };
}
}
} );
auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
ANYTERM( _ ), ANYTERM( RT ), ANYTERM( P ), ANYTERM( _ ), ANYTERM( VA ) ) ) );
auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
// func type param / func arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( funcTypePat ),
ValueToEIR( ValuePattern(
TSID( constant ),
funcTypePat,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto rhsVal = *ValueFromEIR( rhs );
if( IsBuiltinFunc( rhsVal ) )
{
co_yield { rhs, tcc };
co_return;
}
auto wrapped = WrapWithPostprocFunc( rhs, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( tcc.context(), rhsVal );
if( func.isPoison() )
return nullopt;
return ValueToEIR( func );
} );
co_yield { move( wrapped ), tcc };
} );
// tfunc type param / func arg
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( move( tFuncTypePat ) ),
ValueToEIR( ValuePattern(
TSID( constant ),
move( funcTypePat ),
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ldecomp = Decompose( lhs,
Vec(
Lit( "value"_sid ),
SubTerm(),
SubTerm(),
SubTerm(),
Val< LocationId >()
)
);
assert( ldecomp );
auto&& [sort, type, val, locId] = *ldecomp;
auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *ValueFromEIR( type ) );
assert( callPat );
auto rhsVal = *ValueFromEIR( rhs );
auto sig = GetFuncSig( rhsVal );
for( auto&& [s, tcc] : TypeCheck( sig, *callPat, tcc ) )
{
if( IsBuiltinFunc( rhsVal ) )
{
co_yield { ValueToEIR( rhsVal ), tcc };
continue;
}
auto wrapped = WrapWithPostprocFunc( s, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
-> optional< Term >
{
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto func = CompileFunc( tcc.context(), rhsVal );
if( func.isPoison() )
return nullopt;
return ValueToEIR( func );
} );
co_yield { move( wrapped ), tcc };
}
} );
}
}