#include "builtins/builtins.h"
using namespace goose;
using namespace goose::ir;
using namespace goose::llr;
namespace goose::builtins
{
void SetupReferenceUnification( Env& e )
{
auto refTypePattern = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );
auto refTypePatternConstant = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );
auto refTypePatternMutable = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );
auto refTypePatternTemporary = ValueToIRExpr(
Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( temporary ), ANYTERM( _ ) ) ) );
// Common function to process references unification: unify the type and create a reference
// with the unified type and the param reference behavior.
// We define it separatelt because we need to register rules for all the allowed behavior conversion rules
// (any->constant, temporary->mutable), as well as a behavior preserving rule.
auto unifyRefs = []( const Term& lhs, const Term& rhs, UnificationContext& uc ) -> UniGen
{
auto lRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( ValuePatternFromIRExpr( lhs )->type() ) );
auto rhsVal = *ValueFromIRExpr( rhs );
auto rRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( rhsVal.type() ) );
for( auto&& [s, uc] : Unify( lRefType.type(), rRefType.type(), uc ) )
{
co_yield { ValueToIRExpr( Value( ValueToIRExpr( ToValue( ReferenceType( s, lRefType.behavior() ) ) ),
rhsVal.llr() ) ), uc };
}
};
// Behavior preserving reference unification rule.
e.unificationRuleSet()->addSymRule(
ParamPat( refTypePattern ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
unifyRefs
);
// Any behavior -> constant reference unification rule.
e.unificationRuleSet()->addSymRule(
ParamPat( refTypePatternConstant ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
unifyRefs
);
// temporary -> mutable reference unification rule.
e.unificationRuleSet()->addSymRule(
ParamPat( refTypePatternMutable ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePatternTemporary,
ANYTERM( _ ) ) ),
unifyRefs
);
// Reference unification against a param:
// Unify the referenced value with the param.
e.unificationRuleSet()->addSymRule(
ParamPat( ANYTERM( _ ) ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
{
auto refval = *ValueFromIRExpr( rhs );
auto ref = FromValue< Reference >( refval );
if( !ref )
co_return;
auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
llr::Load( ref->address(), ref->type().type() ) )
.setLocationId( refval.locationId() ) );
// Unify the param with the ref's content
co_yield Unify( lhs, content, c );
} );
}
}