Artifact f45e564d170952da18b78e5bc55ccdfb892aa70ea05b0ba3a2fe25061070ae71:
- File
bs/builtins/types/localvar/localvar.cpp
— part of check-in
[7a7e54ac04]
at
2020-07-18 16:25:47
on branch llr-stack-language
— Computed values now carry lists of instructions around, instead of expression trees. Also absolutely nothing works anymore.
Update: closing this branch as I will finally not pursue this. (user: achavasse size: 9257)
#include "builtins/builtins.h" #include "parse/parse.h" using namespace goose::builtins; using namespace goose::llr; using namespace goose::parse; namespace goose::builtins { const Term& LocalVar::PatternAny::GetPattern() { static auto pattern = GetValueType< LocalVar >( HOLE( "_"_sid ) ); return pattern; } const Term& LocalVar::PatternAnyOfTypeT::GetPattern() { static auto pattern = GetValueType< LocalVar >( HOLE( "T"_sid ) ); return pattern; } Value DeclareLocalVar( const Context& c, const Term& type, StringId name, const optional< Value >& initializer ) { const auto& cb = c.codeBuilder(); assert( cb ); const auto& cfg = cb->cfg(); auto index = cfg->getNewTemporaryIndex(); auto bb = cfg->currentBB(); if( !bb ) return PoisonValue(); // If the type is a tuple of type, transform it into the type of a tuple. // I'm hoping that I'm just a huge idiot and not seeing a more obvious and // simpler way that would avoid this confusing distinction... Value typeVal = *ValueFromIRExpr( type ); if( IsTuple( typeVal ) ) typeVal = TupleOfTypesToTupleType( *ValueFromIRExpr( type ) ); LocalVar lv( name, ValueToIRExpr( typeVal ), index ); bb->append( AllocVar( typeVal, index ) ); Value initResult; { DiagnosticsContext dc( 0, "When invoking Initialize." ); if( initializer ) { initResult = InvokeOverloadSet( c, c.env()->extInitialize(), MakeTuple( ToValue( lv ), *initializer ) ); } else { initResult = InvokeOverloadSet( c, c.env()->extInitialize(), MakeTuple( ToValue( lv ) ) ); } } if( !initResult.isPoison() ) { DiagnosticsContext dc2( initResult.locationId(), "When invoking DropValue." ); InvokeOverloadSet( c, c.env()->extDropValue(), MakeTuple( move( initResult ) ) ); } auto locVar = ToValue( lv ); auto identity = AppendToVectorTerm( c.identity(), name ); c.env()->storeValue( identity, ANYTERM( _ ), ValueToIRExpr( locVar ) ); cb->pushLiveValue( locVar, lv.index() ); return locVar; } Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal ) { const auto& cb = c.codeBuilder(); assert( cb ); const auto& cfg = cb->cfg(); auto bb = cfg->currentBB(); if( !bb ) return PoisonValue(); // To infer the type and obtain a suitable initialization function, // we want the declaration to behave as if it were the following function call: // Params: ( $T, _ ( MutRef[$T], initValType ) initFunc ) // Args: ( pat, Initialize ) // // Where pat is the TNamedDecl's type pattern and initValType is the initialization // expression's type. // We construct the above expressions and unify them. The best solution (if any) // will give us the wanted type and the function to invoke to initialize it. // Create the _ texpr. static auto anyTVar = ValueToIRExpr( ToValue( TVar( "_"_sid ) ) ); // The $T texpr. static auto TTVar = ValueToIRExpr( ToValue( TVar( "T"_sid ) ) ); // Create the MutRef[$T] param. static auto mutRefParamPattern = ValueToIRExpr( ToValue( TNamedDecl( GetValueType< Reference >( TTVar, TSID( mut ) ), "ref"_sid ) ) ); auto initValParamPattern = ValueToIRExpr( ToValue( Decl( initVal.type(), "initVal"_sid ) ) ); // Create the _ ( MutRef[pat], initType ) initFunc param. auto initFuncTFTParam = ValueToIRExpr( ToValue( TNamedDecl( ValueToIRExpr( ToValue( TFuncType( anyTVar, VEC( move( mutRefParamPattern ), move( initValParamPattern ) ), make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() ) ) ), "initFunc"_sid ) ) ); // Create our parameter list pattern. auto paramPat = VEC( *BuildTemplateSignature( c, TTVar ), *BuildTemplateSignature( c, initFuncTFTParam ) ); // Create our arg list pattern. auto args = VEC( *BuildTemplateArgPattern( c, typeTExpr ), ValueToIRExpr( ToValue( c.env()->extInitialize() ) ) ); auto us = FindBestTyping( paramPat, args, c ); if( holds_alternative< NoUnification >( us ) ) { // TODO display details DiagnosticsManager::GetInstance().emitErrorMessage( 0, "variable initialization type mismatch." ); return PoisonValue(); } if( holds_alternative< AmbiguousTypeCheck >( us ) ) { // TODO display details DiagnosticsManager::GetInstance().emitErrorMessage( 0, "ambiguous variable type inference." ); return PoisonValue(); } auto&& [s,tcc] = get< TCSol >( us ); // Perform the setup of the type template expression. This will create local bindings // for tvars ($whatever), if any, making them available for further use. // We need to create a temporary context and adjust the identity so that the tvar // bindings will be injected to our parent scope, rather than in our local statement scope. auto parentIdentity = make_shared< Vector >( *get< pvec >( c.identity() ) ); parentIdentity->terms().resize( parentIdentity->terms().size() - 1 ); Context ctxt( c.env(), parentIdentity ); TemplateSetup( ctxt, tcc, typeTExpr ); auto callDecomp = Decompose( s, Vec( SubTerm(), // locvar SubTerm() // initializer ) ); auto&& [type, initializer] = *callDecomp; auto initializerVal = *ValueFromIRExpr( initializer ); auto index = cfg->getNewTemporaryIndex(); // Retrieve the texpr's location and set it on the inferred type. This way if an // error occurs later with it, for instance when calling LowerTypeForRuntime on it during codegen, // it will have a meaningful location for the error message to attach itself on. uint32_t typeLoc = ValueFromIRExpr( typeTExpr )->locationId(); LocalVar lv( name, type, index ); bb->append( AllocVar( ValueFromIRExpr( lv.type() )->setLocationId( typeLoc ), index ) ); DiagnosticsContext dc( 0, "When invoking Initialize." ); auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal, MakeTuple( ToValue( lv ), initVal ) ); if( !initResult.isPoison() ) { DiagnosticsContext dc2( initResult.locationId(), "When invoking DropValue." ); InvokeOverloadSet( c, c.env()->extDropValue(), MakeTuple( move( initResult ) ) ); } auto locVar = ToValue( lv ); if( name != ""_sid ) { auto identity = AppendToVectorTerm( c.identity(), name ); c.env()->storeValue( identity, ANYTERM( _ ), ValueToIRExpr( locVar ) ); } cb->pushLiveValue( locVar, lv.index() ); return locVar; } } namespace goose::ir { const Term& Bridge< LocalVarType >::Type() { return TypeType(); } Value Bridge< LocalVarType >::ToValue( const LocalVarType& t ) { return Value( Type(), TVEC( TSID( ct_type ), TSID( local_var ), t.type() ) ); } Value Bridge< LocalVarType >::ToValue( const Term& type ) { return Value( Type(), TVEC( TSID( ct_type ), TSID( local_var ), type ) ); } optional< LocalVarType > Bridge< LocalVarType >::FromValue( const Value& v ) { auto result = Decompose( v.val(), Vec( Lit( "ct_type"_sid ), Lit( "local_var"_sid ), SubTerm() ) ); if( !result ) return nullopt; auto&& [type] = *result; return LocalVarType( move( type ) ); } Term Bridge< LocalVar >::Type( const Term& type ) { return ValueToIRExpr( ToValue< LocalVarType >( type ) ); } Value Bridge< LocalVar >::ToValue( const LocalVar& lv ) { return Value( Type( lv.type() ), VEC( TERM( lv.name() ), TERM( lv.index() ) ) ); } optional< LocalVar > Bridge< LocalVar >::FromValue( const Value& v ) { if( !v.isConstant() ) return nullopt; auto t = FromValue< LocalVarType >( *ValueFromIRExpr( v.type() ) ); if( !t ) return nullopt; auto result = Decompose( v.val(), Vec( Val< StringId >(), Val< uint32_t >() ) ); if( !result ) return nullopt; auto&& [name,index] = *result; return LocalVar( name, move( t->type() ), index ); } }