#include "builtins/builtins.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
namespace goose::builtins
{
void SetupReferenceTypeChecking( Env& e )
{
auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );
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( temp ), ANYTERM( _ ) ) ) );
// Reference type checking rule.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ParamPat( refTypePattern ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto lRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( ValuePatternFromIRExpr( lhs )->type() ) );
auto rhsVal = *ValuePatternFromIRExpr( rhs );
auto rRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( rhsVal.type() ) );
// Unify the behaviors
for( auto&& [b, tcc] : Unify( lRefType.behavior(), rRefType.behavior(), tcc ) )
{
// Unify the types
for( auto&& [t, tcc] : Unify( lRefType.type(), rRefType.type(), tcc ) )
{
co_yield { ValueToIRExpr( ValuePattern( rhsVal.sort(), ValueToIRExpr( ToValue( ReferenceType( t, b ) ) ),
rhsVal.val() ) ), tcc };
}
}
}
);
// mut -> const reference unification rule.
e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
TSID( const ),
TSID( mut ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
co_yield { TSID( const ), tcc };
}
);
// temp -> const reference unification rule.
e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
TSID( const ),
TSID( temp ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
co_yield { TSID( const ), tcc };
}
);
// temp -> mut reference unification rule.
e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
TSID( mut ),
TSID( temp ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
co_yield { TSID( mut ), tcc };
}
);
// Reference type checking against a param (implicit dereferencing):
// Unify the referenced value with the param.
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ANYTERM( _ ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto refval = *ValueFromIRExpr( rhs );
auto ref = FromValue< Reference >( refval );
if( !ref )
co_return;
auto content = ValueToIRExpr( BuildComputedValue( ref->type().type(),
cir::Load( refval, ref->type().type() ) )
.setLocationId( refval.locationId() ) );
// TypeCheck the param with the ref's content
co_yield TypeCheck( lhs, content, tcc );
} );
// LocalVar type checking against a param (implicit referencing):
// Build a mutable ref value, or just unwrap the locVar if it
// already contains a ref
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
localVarPattern,
ANYTERM( _ ) ) ),
[]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
auto ltype = ValuePatternFromIRExpr( lhs )->type();
auto lvval = *ValueFromIRExpr( rhs );
auto locvar = FromValue< LocalVar >( lvval );
if( !locvar )
co_return;
auto ref = ValueToIRExpr( ToValue( BuildLocalVarMutRef( *locvar ) )
.setLocationId( lvval.locationId() ) );
co_yield TypeCheck( lhs, ref, tcc );
} );
// Implicit referencing of non-variables: build a tempref
e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
refTypePattern,
ANYTERM( _ ) ) ),
ValueToIRExpr( ValuePattern(
ANYTERM( _ ),
ANYTERM( _ ),
ANYTERM( _ ) ) ),
[refTypePattern]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
{
if( !tcc.context().codeBuilder() )
co_return;
if( !tcc.context().codeBuilder()->cfg() )
co_return;
auto lRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( ValuePatternFromIRExpr( lhs )->type() ) );
auto lhsPat = ValueToIRExpr( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );
auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
{
auto valPat = *ValuePatternFromIRExpr( s );
ReferenceType rt( valPat.type(), TSID( temp ) );
auto refPat = ValueToIRExpr( ValuePattern( HOLE( "_"_sid ), ValueToIRExpr( ToValue( rt ) ), HOLE( "_"_sid ) ) );
// TypeCheck the param with the ref
for( auto&& [s,tcc] : TypeCheck( lhs, refPat, tcc ) )
{
assert( tcc.complexity() >= GetComplexity( ParamPat( refTypePattern ) ) );
tcc.subComplexity( GetComplexity( ParamPat( refTypePattern ) ) );
auto wrapped = WrapWithPostprocFunc( VEC( s, rhs ),
[tempIndex]( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
{
auto result = Decompose( t,
Vec(
SubTerm(),
SubTerm()
)
);
assert( result );
auto&& [ref, rhs] = *result;
auto rhsVal = *ValueFromIRExpr( rhs );
auto refPat = *ValuePatternFromIRExpr( ref );
auto rt = *FromValue< ReferenceType >( *ValueFromIRExpr( refPat.type() ) );
return ValueToIRExpr( ToValue( Reference{ move( rt ), TemporaryBaseAddr( tempIndex, rhsVal ) } ) );
} );
co_yield { move( wrapped ), tcc };
}
}
} );
}
}