Goose  Artifact [8876e002af]

Artifact 8876e002afa84f4c261a119b28921e49950cb1d7c6582b247207f6a38e8f923e:

  • File bs/sema/codebuilder.cpp — part of check-in [9b058524b4] at 2021-02-18 19:35:07 on branch trunk — Implemented reference initialization, so reference local variables can now be declared, and added a typechecking rule preventing template variables to bind to reference types.

    Then fixed a MILLION horrible problems caused by all that. Now almost everything works again. *sobs* (user: achavasse size: 3432)


#include "sema.h"
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::sema;
using namespace goose::builtins;

bool CodeBuilder::destroyAndPopCurrentLifetimeScopeValues( const Context& c )
{
    size_t countToPop = 0;
    for( auto rit = m_liveValuesStack.rbegin(); rit != m_liveValuesStack.rend(); ++rit )
    {
        if( rit->m_lifeTimeScopeLevel < m_lifeTimeScopeLevels )
            break;

        if( !destroyLiveValue( c, rit->m_value ) )
        {
            m_liveValuesStack.clear();

            if( cfg() )
                cfg()->poison();
            return false;
        }

        ++countToPop;
    }

    m_liveValuesStack.resize( m_liveValuesStack.size() - countToPop );
    return true;
}

bool CodeBuilder::destroyAllLiveValues( const Context& c )
{
    for( auto rit = m_liveValuesStack.rbegin(); rit != m_liveValuesStack.rend(); ++rit )
    {
        if( !destroyLiveValue( c, rit->m_value ) )
        {
            m_liveValuesStack.clear();

            if( cfg() )
                cfg()->poison();
            return false;
        }
    }

    return true;
}

bool CodeBuilder::destroyAllLiveValuesFromBreakScope( const Context& c, uint32_t breakScopeLevel )
{
    for( auto rit = m_liveValuesStack.rbegin(); rit != m_liveValuesStack.rend(); ++rit )
    {
        if( rit->m_breakableScopeLevel < breakScopeLevel )
            return true;

        if( !destroyLiveValue( c, rit->m_value ) )
        {
            m_liveValuesStack.clear();

            if( cfg() )
                cfg()->poison();
            return false;
        }
    }

    return true;
}

bool CodeBuilder::destroyAllLiveValuesFromContinueScope( const Context& c, uint32_t continueScopeLevel )
{
    for( auto rit = m_liveValuesStack.rbegin(); rit != m_liveValuesStack.rend(); ++rit )
    {
        if( rit->m_continuableScopeLevel < continueScopeLevel )
            return true;

        if( !destroyLiveValue( c, rit->m_value ) )
        {
            m_liveValuesStack.clear();

            if( cfg() )
                cfg()->poison();
            return false;
        }
    }

    return true;
}

bool CodeBuilder::destroyLiveValue( const Context& c, const Value& v )
{
    if( v.isPoison() )
        return false;

    DiagnosticsContext dc( v.locationId(), "When invoking DestroyValue." );
    auto result = InvokeOverloadSet( c, c.env()->extDestroyValue(),
        MakeTuple( v ) );

    return !result.isPoison();
}

void CodeBuilder::extendValueLifetime( uint32_t index )
{
    // Find the live value.
    auto it = find_if( m_liveValuesStack.rbegin(), m_liveValuesStack.rend(),
        [&]( auto&& lv )
        {
            return lv.m_index == index;
        } );

    if( it == m_liveValuesStack.rend() )
        return;

    --it->m_lifeTimeScopeLevel;

    // Look for the first value that belongs to the parent lifetime scope, if any.
    auto last = find_if( it, m_liveValuesStack.rend(),
        [&]( auto&& lv )
        {
            return lv.m_lifeTimeScopeLevel < it->m_lifeTimeScopeLevel;
        } );

    // We want to remove our value from its current position in the stack
    // and reinsert it just after the last value of the parent scope (the one we
    // just found), like it would be if it was inserted in that lifetime scope in the first
    // place.
    // So we perform a rotation of the stack entries by one place from it to last.
    rotate( it, it + 1, last );
}