Goose  Check-in [55beba911a]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:
  • Started work on extensibility api
  • some code cleanup
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 55beba911a4ffa60cb195b8e8d2a9f64aee2220da5aad2a8370e66875ea00437
User & Date: achavasse 2021-09-12 16:48:57.348
Context
2021-09-12
21:38
  • Fixed TermRef
  • Began implementing the api to manipulate the EIR
check-in: 13e21deeef user: achavasse tags: trunk
16:48
  • Started work on extensibility api
  • some code cleanup
check-in: 55beba911a user: achavasse tags: trunk
13:43
Small cleanup check-in: 9345aa6eae user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/builtins.cpp.
20
21
22
23
24
25
26
27
28
29
30
31
32
        e.extConvertFuncArg() = CreateOverloadSet( e, "ConvertFuncArg"_sid );

        SetupBuiltinTypes( e );
        SetupBuiltinOperators( e );
        SetupBuiltinStatements( e );
    }

    const Term& RootIdentity()
    {
        static auto identity = VEC( TSID( g0 ) );
        return identity;
    }
}







|





20
21
22
23
24
25
26
27
28
29
30
31
32
        e.extConvertFuncArg() = CreateOverloadSet( e, "ConvertFuncArg"_sid );

        SetupBuiltinTypes( e );
        SetupBuiltinOperators( e );
        SetupBuiltinStatements( e );
    }

    const Term& RootG0Identity()
    {
        static auto identity = VEC( TSID( g0 ) );
        return identity;
    }
}
Changes to bs/builtins/builtins.h.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

namespace goose::builtins
{
    using namespace eir;
    using namespace sema;
    using namespace diagnostics;

    extern const Term& RootIdentity();
}

#include "codegen/codegen.h"

#include "types/types.h"
#include "operators/operators.h"
#include "statements/statements.h"







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

namespace goose::builtins
{
    using namespace eir;
    using namespace sema;
    using namespace diagnostics;

    extern const Term& RootG0Identity();
}

#include "codegen/codegen.h"

#include "types/types.h"
#include "operators/operators.h"
#include "statements/statements.h"
Changes to bs/builtins/helpers.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose::parse;

namespace goose::builtins
{
    void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule )
    {
        parse::RegisterRule( env, AppendToVectorTerm( RootIdentity(), TERM( name ) ), move( rule ) );
    }

    ptr< cir::BasicBlock > ParseSubStatement( Parser& p, uint32_t precedence )
    {
        auto next = p.resolver()->lookAheadUnresolved();
        if( !next )
            return nullptr;









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose::parse;

namespace goose::builtins
{
    void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule )
    {
        parse::RegisterRule( env, AppendToVectorTerm( RootG0Identity(), TERM( name ) ), move( rule ) );
    }

    ptr< cir::BasicBlock > ParseSubStatement( Parser& p, uint32_t precedence )
    {
        auto next = p.resolver()->lookAheadUnresolved();
        if( !next )
            return nullptr;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        if( holds_alternative< NoUnification >( us ) )
            return ValUnifyError::NoSolution;

        if( holds_alternative< AmbiguousTypeCheck >( us ) )
            return ValUnifyError::Ambiguous;

        auto&& [s,_] = get< TCSol >( us );
        return *ValueFromEIR( s );
    }

    pvec ParseExpressionList( Parser& p, uint32_t precedence, const pvec& pVec )
    {
        while( p.parseExpression( precedence ) )
        {
            auto val = p.popValue();







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        if( holds_alternative< NoUnification >( us ) )
            return ValUnifyError::NoSolution;

        if( holds_alternative< AmbiguousTypeCheck >( us ) )
            return ValUnifyError::Ambiguous;

        auto&& [s,_] = get< TCSol >( us );
        return *EIRToValue( s );
    }

    pvec ParseExpressionList( Parser& p, uint32_t precedence, const pvec& pVec )
    {
        while( p.parseExpression( precedence ) )
        {
            auto val = p.popValue();
Changes to bs/builtins/helpers.h.
1
2
3
4
5
6
7






8
9
10
11
12
13
14
#ifndef GOOSE_BUILTINS_HELPERS_H
#define GOOSE_BUILTINS_HELPERS_H

#include "parse/parse.h"

namespace goose::builtins
{






    extern void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule );

    // Utility function used to parse flow control statements, such as if and loops.
    // This parses a sub statement, which can be enclosed in a brace block or not.
    // It will get its own scope, with visibility rules setup to see the current
    // scope.
    // It returns a pointer to the final basic block generated by the statement.







>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef GOOSE_BUILTINS_HELPERS_H
#define GOOSE_BUILTINS_HELPERS_H

#include "parse/parse.h"

namespace goose::builtins
{
    template< typename T >
    void DefineConstant( sema::Env& env, StringId name, T&& val )
    {
        env.storeValue( AppendToVectorTerm( RootG0Identity(), TERM( name ) ), ANYTERM( _ ), forward< T >( val ) );
    }

    extern void RegisterRule( sema::Env& env, const StringId& name, parse::Rule&& rule );

    // Utility function used to parse flow control statements, such as if and loops.
    // This parses a sub statement, which can be enclosed in a brace block or not.
    // It will get its own scope, with visibility rules setup to see the current
    // scope.
    // It returns a pointer to the final basic block generated by the statement.
Changes to bs/builtins/operators/arith.cpp.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
                {
                    return BuildComputedValue( GetValueType< BigInt >(),
                        Sub( ToValue( BigInt() ), operand ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
                []( auto&& c, auto&& operand ) -> Value
                {
                    auto opTypeVal = *ValueFromEIR( operand.type() );
                    auto opType = *FromValue< IntegerType >( opTypeVal );
                    return BuildComputedValue( operand.type(),
                        Sub( Value( operand.type(), APSInt( opType.m_numBits, false ) ),
                            operand ) );
                } )
            ),
            LeftAssInfixOp( "operator_sub"_sid, precedence::AddSubOp,







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
                {
                    return BuildComputedValue( GetValueType< BigInt >(),
                        Sub( ToValue( BigInt() ), operand ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
                []( auto&& c, auto&& operand ) -> Value
                {
                    auto opTypeVal = *EIRToValue( operand.type() );
                    auto opType = *FromValue< IntegerType >( opTypeVal );
                    return BuildComputedValue( operand.type(),
                        Sub( Value( operand.type(), APSInt( opType.m_numBits, false ) ),
                            operand ) );
                } )
            ),
            LeftAssInfixOp( "operator_sub"_sid, precedence::AddSubOp,
Changes to bs/builtins/operators/assignment.cpp.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

        // Generic function to perform the assignation of a builtin runtime type
        // to a mutable reference of that same type.
        auto BuiltinTypeAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
        {
            G_VAL_ASSERT( lhs, !lhs.isConstant() );

            auto refType = *FromValue< ReferenceType >( *ValueFromEIR( lhs.type() ) );

            if( !ParseTypePredicates( c, *ValueFromEIR( refType.type() ) ) )
                return PoisonValue();

            const auto& cb = c.codeBuilder();
            if( !cb )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
                return PoisonValue();







|

|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

        // Generic function to perform the assignation of a builtin runtime type
        // to a mutable reference of that same type.
        auto BuiltinTypeAssignment = []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
        {
            G_VAL_ASSERT( lhs, !lhs.isConstant() );

            auto refType = *FromValue< ReferenceType >( *EIRToValue( lhs.type() ) );

            if( !ParseTypePredicates( c, *EIRToValue( refType.type() ) ) )
                return PoisonValue();

            const auto& cb = c.codeBuilder();
            if( !cb )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
                return PoisonValue();
Changes to bs/builtins/operators/dollar.cpp.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
        // body, refering to a bound TVar, so we just return the stored value.
        // Otherwise, we're in a template declaration and have to construct a new TVar.
        Term result;

        switch( c.env()->retrieveValue( captureIdentity, c.identity(), result ) )
        {
            case sema::Env::Status::Success:
                return *ValueFromEIR( result );

            case sema::Env::Status::AmbiguousMatch:
                DiagnosticsManager::GetInstance().emitErrorMessage( locationId,
                    format( "unexpected ambiguous match when resolving '${}'.", name ) );
                return PoisonValue();

            default:







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
        // body, refering to a bound TVar, so we just return the stored value.
        // Otherwise, we're in a template declaration and have to construct a new TVar.
        Term result;

        switch( c.env()->retrieveValue( captureIdentity, c.identity(), result ) )
        {
            case sema::Env::Status::Success:
                return *EIRToValue( result );

            case sema::Env::Status::AmbiguousMatch:
                DiagnosticsManager::GetInstance().emitErrorMessage( locationId,
                    format( "unexpected ambiguous match when resolving '${}'.", name ) );
                return PoisonValue();

            default:
Changes to bs/builtins/operators/dot.cpp.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
                    if( !rhs.isConstant() )
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the right operand for the dot operator needs to be a constant." );
                        return PoisonValue();
                    }

                    auto refType = *FromValue< ReferenceType >( *ValueFromEIR( lhs.type() ) );
                    auto tupType = *ValueFromEIR( refType.type() );

                    uint32_t index = *FromValue< uint32_t >( rhs );
                    if( index >= TupleTypeSize( tupType ) )
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the index is out of range." );
                        return PoisonValue();







|
|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
                    if( !rhs.isConstant() )
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the right operand for the dot operator needs to be a constant." );
                        return PoisonValue();
                    }

                    auto refType = *FromValue< ReferenceType >( *EIRToValue( lhs.type() ) );
                    auto tupType = *EIRToValue( refType.type() );

                    uint32_t index = *FromValue< uint32_t >( rhs );
                    if( index >= TupleTypeSize( tupType ) )
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the index is out of range." );
                        return PoisonValue();
Changes to bs/builtins/operators/helpers.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef GOOSE_BUILTINS_OPERATORS_HELPERS_H
#define GOOSE_BUILTINS_OPERATORS_HELPERS_H

#include "builtins/helpers.h"

namespace goose::builtins
{
    using namespace goose::parse;

    template< typename... R >
    void BuildParseRule( sema::Env& env, const StringId& name, R&&... ruleBuilders )
    {
        parse::BuildParseRule( env, name, AppendToVectorTerm( RootIdentity(), TERM( name ) ),
            forward< R >( ruleBuilders )... );
    }

    struct UnaryOpTag {};
    struct BinaryOpTag {};

    template< typename... R >












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef GOOSE_BUILTINS_OPERATORS_HELPERS_H
#define GOOSE_BUILTINS_OPERATORS_HELPERS_H

#include "builtins/helpers.h"

namespace goose::builtins
{
    using namespace goose::parse;

    template< typename... R >
    void BuildParseRule( sema::Env& env, const StringId& name, R&&... ruleBuilders )
    {
        parse::BuildParseRule( env, name, AppendToVectorTerm( RootG0Identity(), TERM( name ) ),
            forward< R >( ruleBuilders )... );
    }

    struct UnaryOpTag {};
    struct BinaryOpTag {};

    template< typename... R >
Changes to bs/builtins/operators/intrinsic.cpp.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
                {
                    auto ovl = *FromValue< Overload >( operand );

                    if( !ovl.callee().isConstant() )
                        return PoisonValue();

                    auto result = InvokeOverloadSet( c, intrinsicOp,
                        MakeTuple( *ValueFromEIR( ovl.callee().type() ) ) );

                    if( result.isPoison() )
                        return PoisonValue();

                    return ToValue(
                        Overload( ovl.ovlSet(),
                        Value( ValueToEIR( result ), ovl.callee().val() ).setLocationId( ovl.callee().locationId()







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
                {
                    auto ovl = *FromValue< Overload >( operand );

                    if( !ovl.callee().isConstant() )
                        return PoisonValue();

                    auto result = InvokeOverloadSet( c, intrinsicOp,
                        MakeTuple( *EIRToValue( ovl.callee().type() ) ) );

                    if( result.isPoison() )
                        return PoisonValue();

                    return ToValue(
                        Overload( ovl.ovlSet(),
                        Value( ValueToEIR( result ), ovl.callee().val() ).setLocationId( ovl.callee().locationId()
Changes to bs/builtins/operators/logic.cpp.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

        BuildParseRule( e, "~"_sid,
            PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),

                ForType< CustomPattern< IntegerType, IntegerType::Pattern > >( []( auto&& c, auto&& operand ) -> Value
                {
                    auto opTypeVal = *ValueFromEIR( operand.type() );
                    auto opType = *FromValue< IntegerType >( opTypeVal );
                    return BuildComputedValue( operand.type(),
                        Xor( operand,
                            Value( operand.type(), APSInt::getMaxValue( opType.m_numBits, true ) )
                        ) );
                } )
            )







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

        BuildParseRule( e, "~"_sid,
            PrefixOp( "operator_bitwise_not"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),

                ForType< CustomPattern< IntegerType, IntegerType::Pattern > >( []( auto&& c, auto&& operand ) -> Value
                {
                    auto opTypeVal = *EIRToValue( operand.type() );
                    auto opType = *FromValue< IntegerType >( opTypeVal );
                    return BuildComputedValue( operand.type(),
                        Xor( operand,
                            Value( operand.type(), APSInt::getMaxValue( opType.m_numBits, true ) )
                        ) );
                } )
            )
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
                    auto rhsIndex = cfg->getNewTemporaryIndex();
                    pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
                    pRhsBB->setTerminator( Branch( pSuccBB ) );

                    auto resultIndex = cfg->getNewTemporaryIndex();

                    // Build the Phi instruction that will collect the final result.
                    auto phi = Phi( *ValueFromEIR( GetValueType< bool >() ), 2,
                        resultIndex );

                    // If coming directly from the lhs BB, we know the result is true.
                    phi.setIncoming( predBB, ToValue( true ) );

                    // Otherwise, the result is whatever was computed by the rhs block.
                    phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),







|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
                    auto rhsIndex = cfg->getNewTemporaryIndex();
                    pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
                    pRhsBB->setTerminator( Branch( pSuccBB ) );

                    auto resultIndex = cfg->getNewTemporaryIndex();

                    // Build the Phi instruction that will collect the final result.
                    auto phi = Phi( *EIRToValue( GetValueType< bool >() ), 2,
                        resultIndex );

                    // If coming directly from the lhs BB, we know the result is true.
                    phi.setIncoming( predBB, ToValue( true ) );

                    // Otherwise, the result is whatever was computed by the rhs block.
                    phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
                    auto rhsIndex = cfg->getNewTemporaryIndex();
                    pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
                    pRhsBB->setTerminator( Branch( pSuccBB ) );

                    auto resultIndex = cfg->getNewTemporaryIndex();

                    // Build the Phi instruction that will collect the final result.
                    auto phi = Phi( *ValueFromEIR( GetValueType< bool >() ), 2,
                        resultIndex );

                    // If coming directly from the lhs BB, we know the result is true.
                    phi.setIncoming( predBB, ToValue( false ) );

                    // Otherwise, the result is whatever was computed by the rhs block.
                    phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),







|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
                    auto rhsIndex = cfg->getNewTemporaryIndex();
                    pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
                    pRhsBB->setTerminator( Branch( pSuccBB ) );

                    auto resultIndex = cfg->getNewTemporaryIndex();

                    // Build the Phi instruction that will collect the final result.
                    auto phi = Phi( *EIRToValue( GetValueType< bool >() ), 2,
                        resultIndex );

                    // If coming directly from the lhs BB, we know the result is true.
                    phi.setIncoming( predBB, ToValue( false ) );

                    // Otherwise, the result is whatever was computed by the rhs block.
                    phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
                    auto cfg = cb->cfg();
                    assert( cfg );

                    // Shifting for a number of bits equal or larger than the bitsize
                    // of lhs is an undefined behavior, so we require verification that
                    // it won't happen.
                    // Extract the integer type of lhs to retreieve its bit size.
                    auto lhsType = *FromValue< IntegerType >( *ValueFromEIR( lhs.type() ) );
                    auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );








|







234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
                    auto cfg = cb->cfg();
                    assert( cfg );

                    // Shifting for a number of bits equal or larger than the bitsize
                    // of lhs is an undefined behavior, so we require verification that
                    // it won't happen.
                    // Extract the integer type of lhs to retreieve its bit size.
                    auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
                    auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
                    auto cfg = cb->cfg();
                    assert( cfg );

                    // Shifting for a number of bits equal or larger than the bitsize
                    // of lhs is an undefined behavior, so we require verification that
                    // it won't happen.
                    // Extract the integer type of lhs to retreieve its bit size.
                    auto lhsType = *FromValue< IntegerType >( *ValueFromEIR( lhs.type() ) );
                    auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );








|







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
                    auto cfg = cb->cfg();
                    assert( cfg );

                    // Shifting for a number of bits equal or larger than the bitsize
                    // of lhs is an undefined behavior, so we require verification that
                    // it won't happen.
                    // Extract the integer type of lhs to retreieve its bit size.
                    auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
                    auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
                    auto cfg = cb->cfg();
                    assert( cfg );

                    // Shifting for a number of bits equal or larger than the bitsize
                    // of lhs is an undefined behavior, so we require verification that
                    // it won't happen.
                    // Extract the integer type of lhs to retreieve its bit size.
                    auto lhsType = *FromValue< IntegerType >( *ValueFromEIR( lhs.type() ) );
                    auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );








|







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
                    auto cfg = cb->cfg();
                    assert( cfg );

                    // Shifting for a number of bits equal or larger than the bitsize
                    // of lhs is an undefined behavior, so we require verification that
                    // it won't happen.
                    // Extract the integer type of lhs to retreieve its bit size.
                    auto lhsType = *FromValue< IntegerType >( *EIRToValue( lhs.type() ) );
                    auto bitSizeValue = Value( rhs.type(), APSInt::get( lhsType.m_numBits) );

                    auto cond = ULT( rhs, bitSizeValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the shift amount may be equal or greater than the bitsize." );

Changes to bs/builtins/operators/tuple.h.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
                    }

                    auto result = EmptyTuple();

                    ForEachInTuples( lhs, rhs, [&]( auto&& lhs, auto&& rhs )
                    {
                        auto r = InvokeOverloadSet( c, pOvlSet,
                            MakeTuple( *ValueFromEIR( lhs ), *ValueFromEIR( rhs ) ) );

                        // Super inefficient, but that's far from the biggest such problem.
                        // This is just the bootstrap compiler anyway. Should hopefully be able to
                        // easily make more optimized stuff when rewriting the self hosted compiler,
                        // some day far away in the future.
                        result = AppendToTuple( result, r );
                        return true;







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
                    }

                    auto result = EmptyTuple();

                    ForEachInTuples( lhs, rhs, [&]( auto&& lhs, auto&& rhs )
                    {
                        auto r = InvokeOverloadSet( c, pOvlSet,
                            MakeTuple( *EIRToValue( lhs ), *EIRToValue( rhs ) ) );

                        // Super inefficient, but that's far from the biggest such problem.
                        // This is just the bootstrap compiler anyway. Should hopefully be able to
                        // easily make more optimized stuff when rewriting the self hosted compiler,
                        // some day far away in the future.
                        result = AppendToTuple( result, r );
                        return true;
Changes to bs/builtins/statements/break.cpp.
35
36
37
38
39
40
41
42
43
44
45
46
47
            // Emit cleanups for all live variables in the scopes that we are breaking through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->breakableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Break( cb->breakableScopeLevels() ) );
            return true;
        };

        Rule r( handleBreak );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( break ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


35
36
37
38
39
40
41
42



43
44
            // Emit cleanups for all live variables in the scopes that we are breaking through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->breakableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Break( cb->breakableScopeLevels() ) );
            return true;
        };

        RegisterRule( e, "break"_sid, Rule( handleBreak ) );



    }
}
Changes to bs/builtins/statements/continue.cpp.
35
36
37
38
39
40
41
42
43
44
45
46
47
            // Emit cleanups for all live variables in the scopes that we are continuing through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->continuableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Continue( cb->continuableScopeLevels() ) );
            return true;
        };

        Rule r( handleContinue );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( continue ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


35
36
37
38
39
40
41
42



43
44
            // Emit cleanups for all live variables in the scopes that we are continuing through.
            cb->destroyAllLiveValuesFromBreakScope( p.context(), cb->continuableScopeLevels() );

            cfg->currentBB()->setTerminator( cir::Continue( cb->continuableScopeLevels() ) );
            return true;
        };

        RegisterRule( e, "continue"_sid, Rule( handleContinue ) );



    }
}
Changes to bs/builtins/statements/hif.cpp.
125
126
127
128
129
130
131
132
133
134
135
136
137
                    }
                }
            }

            return true;
        };

        Rule r( handleHIf );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( #if ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


125
126
127
128
129
130
131
132



133
134
                    }
                }
            }

            return true;
        };

        RegisterRule( e, "#if"_sid, Rule( handleHIf ) );



    }
}
Changes to bs/builtins/statements/if.cpp.
133
134
135
136
137
138
139
140
141
142
143
144
145
            // successor block was created: it means all our code paths
            // are already terminated and there is no point in emitting any more
            // instructions.
            cfg->setCurrentBB( pSuccBB );
            return true;
        };

        Rule r( handleIf );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( if ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


133
134
135
136
137
138
139
140



141
142
            // successor block was created: it means all our code paths
            // are already terminated and there is no point in emitting any more
            // instructions.
            cfg->setCurrentBB( pSuccBB );
            return true;
        };

        RegisterRule( e, "if"_sid, Rule( handleIf ) );



    }
}
Changes to bs/builtins/statements/return.cpp.
79
80
81
82
83
84
85
86
87
88
89
90
91
                return true;
            }

            cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
            return true;
        };

        Rule r( handleReturn );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( return ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


79
80
81
82
83
84
85
86



87
88
                return true;
            }

            cb->emitTerminator( p.resolver()->currentLocation(), cir::Ret( get< Value >( converted ) ) );
            return true;
        };

        RegisterRule( e, "return"_sid, Rule( handleReturn ) );



    }
}
Changes to bs/builtins/statements/using.cpp.
1
2
3

4
5
6
7
8
9
10
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"


using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{



>







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
75
76
77
78
79
80
81
82
83
84
85
86
87
                return true;
            }

            context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( *np.popValue() ) );
            return true;
        };

        Rule r( handleUsing );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( using ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


76
77
78
79
80
81
82
83



84
85
                return true;
            }

            context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( *np.popValue() ) );
            return true;
        };

        RegisterRule( e, "using"_sid, Rule( handleUsing ) );



    }
}
Changes to bs/builtins/statements/while.cpp.
138
139
140
141
142
143
144
145
146
147
148
149
150
                get< Value >( converted ),
                pBodyBB, pSuccBB ) );

            cfg->setCurrentBB( pSuccBB );
            return true;
        };

        Rule r( handleWhile );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


138
139
140
141
142
143
144
145



146
147
                get< Value >( converted ),
                pBodyBB, pSuccBB ) );

            cfg->setCurrentBB( pSuccBB );
            return true;
        };

        RegisterRule( e, "while"_sid, Rule( handleWhile ) );



    }
}
Changes to bs/builtins/types/basic.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "builtins/builtins.h"
#include "builtins/helpers.h"

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

namespace goose::builtins
{
    void SetupBasicTypes( Env& e )
    {
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( type ) ), ANYTERM( _ ), TypeType() );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( void ) ), ANYTERM( _ ), GetValueType< void >() );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( bool ) ), ANYTERM( _ ), GetValueType< bool >() );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_int ) ), ANYTERM( _ ), GetValueType< BigInt >() );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_char ) ), ANYTERM( _ ), GetValueType< char32_t >() );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ct_string ) ), ANYTERM( _ ), GetValueType< string >() );

        // bool literals
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( true ) ), ANYTERM( _ ), ValueToEIR( ToValue( true ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( false ) ), ANYTERM( _ ), ValueToEIR( ToValue( false ) ) );

        // _ and var are both aliases for an anonymous tvar ($_)
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( _ ) ), ANYTERM( _ ), ValueToEIR( ToValue( TVar( "_"_sid ) ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( var ) ), ANYTERM( _ ), ValueToEIR( ToValue( TVar( "_"_sid ) ) ) );
    }

    const Term& ValuePatternT::GetPattern()
    {
        static auto pattern = HOLE( "T"_sid, TSID( tvar ) );
        return pattern;
    }











|
|
|
|
|
|


|
|


|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "builtins/builtins.h"
#include "builtins/helpers.h"

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

namespace goose::builtins
{
    void SetupBasicTypes( Env& e )
    {
        DefineConstant( e, "type"_sid, TypeType() );
        DefineConstant( e, "void"_sid, GetValueType< void >() );
        DefineConstant( e, "bool"_sid, GetValueType< bool >() );
        DefineConstant( e, "ct_int"_sid, GetValueType< BigInt >() );
        DefineConstant( e, "ct_char"_sid, GetValueType< char32_t >() );
        DefineConstant( e, "ct_string"_sid, GetValueType< string >() );

        // bool literals
        DefineConstant( e, "true"_sid, ValueToEIR( ToValue( true ) ) );
        DefineConstant( e, "false"_sid, ValueToEIR( ToValue( false ) ) );

        // _ and var are both aliases for an anonymous tvar ($_)
        DefineConstant( e, "_"_sid, ValueToEIR( ToValue( TVar( "_"_sid ) ) ) );
        DefineConstant( e, "var"_sid, ValueToEIR( ToValue( TVar( "_"_sid ) ) ) );
    }

    const Term& ValuePatternT::GetPattern()
    {
        static auto pattern = HOLE( "T"_sid, TSID( tvar ) );
        return pattern;
    }
Changes to bs/builtins/types/constrainedfunc/constrainedfunc.cpp.
38
39
40
41
42
43
44
45
46
47
        if( !result )
            return nullopt;

        auto&& [constraintPat, pInvRule, func] = *result;
        return builtins::ConstrainedFunc(
            *Unquote( constraintPat ),
            static_pointer_cast< InvocationRule >( pInvRule ),
            *ValueFromEIR( func ) );
    }
}







|


38
39
40
41
42
43
44
45
46
47
        if( !result )
            return nullopt;

        auto&& [constraintPat, pInvRule, func] = *result;
        return builtins::ConstrainedFunc(
            *Unquote( constraintPat ),
            static_pointer_cast< InvocationRule >( pInvRule ),
            *EIRToValue( func ) );
    }
}
Changes to bs/builtins/types/constrainedfunc/typecheck.cpp.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildCallPatternFromFuncType( *ValueFromEIR( type ) );

            auto rhsVal = *ValueFromEIR( rhs );
            auto cfunc = FromValue< ConstrainedFunc >( rhsVal );
            assert( cfunc );

            auto localC = tcc;
            for( auto&& [s, tcc] : TypeCheck( callPat, cfunc->constraintPat(), localC ) )
            {
                if( Postprocess( s, tcc ) )







|

|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildCallPatternFromFuncType( *EIRToValue( type ) );

            auto rhsVal = *EIRToValue( rhs );
            auto cfunc = FromValue< ConstrainedFunc >( rhsVal );
            assert( cfunc );

            auto localC = tcc;
            for( auto&& [s, tcc] : TypeCheck( callPat, cfunc->constraintPat(), localC ) )
            {
                if( Postprocess( s, tcc ) )
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
                    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 cfunc = FromValue< ConstrainedFunc >( rhsVal );
            assert( cfunc );

            auto localC = tcc;
            for( auto&& [s, tcc] : TypeCheck( *callPat, cfunc->constraintPat(), localC ) )
            {
                if( Postprocess( s, tcc ) )







|


|







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *EIRToValue( type ) );
            assert( callPat );

            auto rhsVal = *EIRToValue( rhs );
            auto cfunc = FromValue< ConstrainedFunc >( rhsVal );
            assert( cfunc );

            auto localC = tcc;
            for( auto&& [s, tcc] : TypeCheck( *callPat, cfunc->constraintPat(), localC ) )
            {
                if( Postprocess( s, tcc ) )
Changes to bs/builtins/types/decl.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::builtins
{
    bool IsDecl( const Value& d )
    {
        auto typeVal = ValueFromEIR( d.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "decl"_sid ),
                SubTerm()
            )
        );









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include "builtins/builtins.h"

using namespace goose::builtins;

namespace goose::builtins
{
    bool IsDecl( const Value& d )
    {
        auto typeVal = EIRToValue( d.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "decl"_sid ),
                SubTerm()
            )
        );

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    Value Bridge< Decl >::ToValue( const Decl& d )
    {
        return Value( Type( d.type() ), TERM( d.name() ) );
    }

    optional< Decl > Bridge< Decl >::FromValue( const Value& v )
    {
        auto typeVal = ValueFromEIR( v.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "decl"_sid ),
                SubTerm()
            )
        );








|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    Value Bridge< Decl >::ToValue( const Decl& d )
    {
        return Value( Type( d.type() ), TERM( d.name() ) );
    }

    optional< Decl > Bridge< Decl >::FromValue( const Value& v )
    {
        auto typeVal = EIRToValue( v.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "decl"_sid ),
                SubTerm()
            )
        );

Changes to bs/builtins/types/extensibility/valuewrapper.cpp.
21
22
23
24
25
26
27
28
29
30
        if( v.type() != Type() )
            return nullopt;

        auto uq = Unquote( v.val() );
        if( !uq )
            return nullopt;

        return ValueFromEIR( *uq );
    }
}







|


21
22
23
24
25
26
27
28
29
30
        if( v.type() != Type() )
            return nullopt;

        auto uq = Unquote( v.val() );
        if( !uq )
            return nullopt;

        return EIRToValue( *uq );
    }
}
Changes to bs/builtins/types/func/bfunc.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"

namespace goose::builtins
{
    bool IsBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // return type






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"

namespace goose::builtins
{
    bool IsBuiltinFunc( const Value& func )
    {
        auto funcType = EIRToValue( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // return type
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
        );

        return !!decomp;
    }

    bool IsNonEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // flags
            )
        );

        return !!decomp;
    }

    bool IsEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin_eager"_sid ),
                SubTerm(),  // return type







|


















|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
        );

        return !!decomp;
    }

    bool IsNonEagerBuiltinFunc( const Value& func )
    {
        auto funcType = EIRToValue( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin"_sid ),
                SubTerm(),  // return type
                SubTerm(),  // param types
                SubTerm(),  // verif info
                SubTerm()   // flags
            )
        );

        return !!decomp;
    }

    bool IsEagerBuiltinFunc( const Value& func )
    {
        auto funcType = EIRToValue( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "builtin_eager"_sid ),
                SubTerm(),  // return type
Changes to bs/builtins/types/func/bfunc.inl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#ifndef GOOSE_BUILTINS_TYPES_BFUNC_INL
#define GOOSE_BUILTINS_TYPES_BFUNC_INL

namespace goose::builtins
{
    template< typename FT, typename F >
    ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, const StringId& name, F&& func )
    {
        ptr< OverloadSet > pOvlSet;
        auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );

        Term result;

        switch( env.retrieveValue( identity, RootIdentity(), result ) )
        {
            case sema::Env::Status::Success:
                pOvlSet = *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );
                break;

            case sema::Env::Status::NoMatch:
                pOvlSet = make_shared< OverloadSet >( identity );
                env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
                break;

            case sema::Env::Status::AmbiguousMatch:
                G_ERROR( "ambiguous match while registering builtin func "s + name.str() );
        }

        return RegisterBuiltinFunc< FT >( env, pOvlSet, forward< F >( func ) );
    }

    template< typename FT, typename F >
    ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, ptr< OverloadSet > pOvlSet, F&& func )
    {
        auto fvi = make_shared< builtins::FuncVerificationInfos >( RootIdentity() );

        if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
            G_ERROR( "duplicate overload registered for builtin func." );

        return fvi;
    }
}









|



|


|

















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#ifndef GOOSE_BUILTINS_TYPES_BFUNC_INL
#define GOOSE_BUILTINS_TYPES_BFUNC_INL

namespace goose::builtins
{
    template< typename FT, typename F >
    ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, const StringId& name, F&& func )
    {
        ptr< OverloadSet > pOvlSet;
        auto identity = AppendToVectorTerm( RootG0Identity(), TERM( name ) );

        Term result;

        switch( env.retrieveValue( identity, RootG0Identity(), result ) )
        {
            case sema::Env::Status::Success:
                pOvlSet = *FromValue< ptr< OverloadSet > >( *EIRToValue( result ) );
                break;

            case sema::Env::Status::NoMatch:
                pOvlSet = make_shared< OverloadSet >( identity );
                env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
                break;

            case sema::Env::Status::AmbiguousMatch:
                G_ERROR( "ambiguous match while registering builtin func "s + name.str() );
        }

        return RegisterBuiltinFunc< FT >( env, pOvlSet, forward< F >( func ) );
    }

    template< typename FT, typename F >
    ptr< FuncVerificationInfos > RegisterBuiltinFunc( Env& env, ptr< OverloadSet > pOvlSet, F&& func )
    {
        auto fvi = make_shared< builtins::FuncVerificationInfos >( RootG0Identity() );

        if( !pOvlSet->add( env, ToValue< FT >( forward< F >( func ), fvi ), GetFuncInvocationRule() ) )
            G_ERROR( "duplicate overload registered for builtin func." );

        return fvi;
    }
}
Changes to bs/builtins/types/func/bintrinsic.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"

namespace goose::builtins
{
    bool IsBuiltinIntrinsicFunc( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "intrinsic_builtin"_sid ),
                SubTerm(),  // return type






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"

namespace goose::builtins
{
    bool IsBuiltinIntrinsicFunc( const Value& func )
    {
        auto funcType = EIRToValue( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "intrinsic_builtin"_sid ),
                SubTerm(),  // return type
Changes to bs/builtins/types/func/build.cpp.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        ForEachInTuple( params, [&]( auto&& param )
        {
            if( IsDecl( param ) )
            {
                auto decl = *FromValue< Decl >( param );

                auto type = InvokeOverloadSet( c, c.env()->extConvertFuncParam(),
                    MakeTuple( *ValueFromEIR( decl.type() ) ) );
                if( type.isPoison() )
                {
                    failed = true;
                    return false;
                }

                tv->append( BuildParamPat( c, type, param.locationId() ) );







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        ForEachInTuple( params, [&]( auto&& param )
        {
            if( IsDecl( param ) )
            {
                auto decl = *FromValue< Decl >( param );

                auto type = InvokeOverloadSet( c, c.env()->extConvertFuncParam(),
                    MakeTuple( *EIRToValue( decl.type() ) ) );
                if( type.isPoison() )
                {
                    failed = true;
                    return false;
                }

                tv->append( BuildParamPat( c, type, param.locationId() ) );
Changes to bs/builtins/types/func/compile.cpp.
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
                    Val< LocationId >()
                )
            );
            assert( result );

            auto&& [sort, type, val, locId] = *result;

            if( !ParseTypePredicates( c, *ValueFromEIR( type ) ) )
                predsOk = false;

            return true;
        } );

        if( !predsOk )
            return false;

        // Perform lazy parsing on return type predicates
        if( !ParseTypePredicates( c, *ValueFromEIR( f.type().returnType() ) ) )
            return false;

        // If the function already have a cir body, nothing to do.
        if( pFuncCIR->body() )
            return true;

        if( !f.tokens() )







|









|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
                    Val< LocationId >()
                )
            );
            assert( result );

            auto&& [sort, type, val, locId] = *result;

            if( !ParseTypePredicates( c, *EIRToValue( type ) ) )
                predsOk = false;

            return true;
        } );

        if( !predsOk )
            return false;

        // Perform lazy parsing on return type predicates
        if( !ParseTypePredicates( c, *EIRToValue( f.type().returnType() ) ) )
            return false;

        // If the function already have a cir body, nothing to do.
        if( pFuncCIR->body() )
            return true;

        if( !f.tokens() )
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        // TODO: for intrinsic functions, we need to expose the CodeBuilder
        // as it is an ilmplicit extra param
        uint32_t varId = 0;
        for( auto&& t : f.paramsDecl()->terms() )
        {
            auto param = *ValueFromEIR( t );

            if( !IsDecl( param ) )
                continue;

            auto decl = *FromValue< Decl >( param );
            auto paramIdentity = AppendToVectorTerm( bodyIdentity, TERM( decl.name() ) );








|







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        // TODO: for intrinsic functions, we need to expose the CodeBuilder
        // as it is an ilmplicit extra param
        uint32_t varId = 0;
        for( auto&& t : f.paramsDecl()->terms() )
        {
            auto param = *EIRToValue( t );

            if( !IsDecl( param ) )
                continue;

            auto decl = *FromValue< Decl >( param );
            auto paramIdentity = AppendToVectorTerm( bodyIdentity, TERM( decl.name() ) );

Changes to bs/builtins/types/func/func.cpp.
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    }

    bool IsIntrinsicFunc( const Value& f )
    {
        if( !f.isConstant() )
            return false;

        auto typeVal = ValueFromEIR( f.type() );
        return typeVal && IsIntrinsicFuncType( *typeVal );
    }

    bool IsFuncType( const Value& t )
    {
        auto result = Decompose( t.val(),
            Vec(







|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    }

    bool IsIntrinsicFunc( const Value& f )
    {
        if( !f.isConstant() )
            return false;

        auto typeVal = EIRToValue( f.type() );
        return typeVal && IsIntrinsicFuncType( *typeVal );
    }

    bool IsFuncType( const Value& t )
    {
        auto result = Decompose( t.val(),
            Vec(
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
        );

        return !!result;
    }

    Term GetFuncSig( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );
        return GetFuncSigFromType( *funcType );
    }

    Term GetFuncSigFromType( const Value& funcType )
    {
        auto typeDecomp = Decompose( funcType.val(),







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
        );

        return !!result;
    }

    Term GetFuncSig( const Value& func )
    {
        auto funcType = EIRToValue( func.type() );
        assert( funcType );
        return GetFuncSigFromType( *funcType );
    }

    Term GetFuncSigFromType( const Value& funcType )
    {
        auto typeDecomp = Decompose( funcType.val(),
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return PrependToVectorTerm( *Unquote( ptypes ), rtype );
    }

    Term GetFuncRType( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );

        auto typeDecomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                SubTerm(),  // kind
                SubTerm(),  // return type







|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return PrependToVectorTerm( *Unquote( ptypes ), rtype );
    }

    Term GetFuncRType( const Value& func )
    {
        auto funcType = EIRToValue( func.type() );
        assert( funcType );

        auto typeDecomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                SubTerm(),  // kind
                SubTerm(),  // return type
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
            return ParamListKind::Invalid;

        auto result = ParamListKind::Regular;

        const auto& vec = *get< pvec >( tup.val() );
        for( auto&& x : vec.terms() )
        {
            auto v = ValueFromEIR( x );
            if( !v )
                return ParamListKind::Invalid;

            if( IsTDecl( *v ) || IsTNamedDecl( *v ) || IsTExpr( *v ) )
                result = ParamListKind::Template;
            else if( !IsDecl( *v ) && !v->isConstant() )
                return ParamListKind::Invalid;







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
            return ParamListKind::Invalid;

        auto result = ParamListKind::Regular;

        const auto& vec = *get< pvec >( tup.val() );
        for( auto&& x : vec.terms() )
        {
            auto v = EIRToValue( x );
            if( !v )
                return ParamListKind::Invalid;

            if( IsTDecl( *v ) || IsTNamedDecl( *v ) || IsTExpr( *v ) )
                result = ParamListKind::Template;
            else if( !IsDecl( *v ) && !v->isConstant() )
                return ParamListKind::Invalid;
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        bool failed = false;
        ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
        {
            auto vp = ValuePatternFromEIR( p );
            if( vp->val() == HOLE( "_"_sid ) )
            {
                auto convertedArg = InvokeOverloadSet( c, c.env()->extConvertFuncArg(),
                    MakeTuple( *ValueFromEIR( a ), *ValueFromEIR( vp->type() ) ) );
                if( convertedArg.isPoison() )
                {
                    failed = true;
                    return false;
                }

                av->append( ValueToEIR( convertedArg ) );







|







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        bool failed = false;
        ForEachInVectorTerms( ft.params(), unifiedArgs, [&]( auto&& p, auto&& a )
        {
            auto vp = ValuePatternFromEIR( p );
            if( vp->val() == HOLE( "_"_sid ) )
            {
                auto convertedArg = InvokeOverloadSet( c, c.env()->extConvertFuncArg(),
                    MakeTuple( *EIRToValue( a ), *EIRToValue( vp->type() ) ) );
                if( convertedArg.isPoison() )
                {
                    failed = true;
                    return false;
                }

                av->append( ValueToEIR( convertedArg ) );
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

        bool failed = false;
        ForEachInVectorTerms( ft.params(), typeCheckedArgs, [&]( auto&& p, auto&& a )
        {
            auto vp = ValuePatternFromEIR( p );
            if( vp->val() == HOLE( "_"_sid ) )
            {
                auto wrappedArg = ToValue( ValueWrapper( *ValueFromEIR( a ) ) );
                av->append( ValueToEIR( wrappedArg ) );
            }

            return true;
        } );

        if( failed )







|







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

        bool failed = false;
        ForEachInVectorTerms( ft.params(), typeCheckedArgs, [&]( auto&& p, auto&& a )
        {
            auto vp = ValuePatternFromEIR( p );
            if( vp->val() == HOLE( "_"_sid ) )
            {
                auto wrappedArg = ToValue( ValueWrapper( *EIRToValue( a ) ) );
                av->append( ValueToEIR( wrappedArg ) );
            }

            return true;
        } );

        if( failed )
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
    }

    optional< Func > Bridge< Func >::FromValue( const Value& v )
    {
        if( !v.isConstant() || v.isPoison() )
            return nullopt;

        auto funcTypeVal = ValueFromEIR( v.type() );
        if( !funcTypeVal )
            return nullopt;

        auto funcType = ::FromValue< FuncType >( *funcTypeVal );
        if( !funcType )
            return nullopt;








|







301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
    }

    optional< Func > Bridge< Func >::FromValue( const Value& v )
    {
        if( !v.isConstant() || v.isPoison() )
            return nullopt;

        auto funcTypeVal = EIRToValue( v.type() );
        if( !funcTypeVal )
            return nullopt;

        auto funcType = ::FromValue< FuncType >( *funcTypeVal );
        if( !funcType )
            return nullopt;

Changes to bs/builtins/types/func/invoke.cpp.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

                if( IsBuiltinFunc( preparedCallee ) )
                    return BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( typeCheckedArgs ) ) );

                if( IsBuiltinIntrinsicFunc( preparedCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( preparedCallee )( c, move( typeCheckedArgs ) );

                auto ft = *FromValue< FuncType >( *ValueFromEIR( preparedCallee.type() ) );

                if( ft.intrinsic() )
                {
                    // Intrinsic call: we insert the code builder wrapper as first param,
                    // wrap all args with ValueWrapper, and execute the function directly.
                    auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
                    if( !argList )







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

                if( IsBuiltinFunc( preparedCallee ) )
                    return BuildComputedValue( typeCheckedRType, cir::Call( preparedCallee, move( typeCheckedArgs ) ) );

                if( IsBuiltinIntrinsicFunc( preparedCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( preparedCallee )( c, move( typeCheckedArgs ) );

                auto ft = *FromValue< FuncType >( *EIRToValue( preparedCallee.type() ) );

                if( ft.intrinsic() )
                {
                    // Intrinsic call: we insert the code builder wrapper as first param,
                    // wrap all args with ValueWrapper, and execute the function directly.
                    auto argList = BuildArgListForIntrinsicCall( c, ft, typeCheckedArgs );
                    if( !argList )
Changes to bs/builtins/types/func/lower.cpp.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    optional< FuncType > LowerFunctionTypeForRuntime( const Context& c, const FuncType& ft )
    {
        // If the passed function already have an associated llvm type,
        // we have nothing to do.
        if( ft.llvmType() )
            return ft;

        auto rt = LowerTypeForRuntime( c, *ValueFromEIR( ft.returnType() ) );
        if( !rt )
            return nullopt;

        vector< llvm::Type* > paramTypes;
        const auto& paramVec = *get< pvec >( ft.params() );
        paramTypes.reserve( paramVec.terms().size() );








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    optional< FuncType > LowerFunctionTypeForRuntime( const Context& c, const FuncType& ft )
    {
        // If the passed function already have an associated llvm type,
        // we have nothing to do.
        if( ft.llvmType() )
            return ft;

        auto rt = LowerTypeForRuntime( c, *EIRToValue( ft.returnType() ) );
        if( !rt )
            return nullopt;

        vector< llvm::Type* > paramTypes;
        const auto& paramVec = *get< pvec >( ft.params() );
        paramTypes.reserve( paramVec.terms().size() );

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
            {
                success = false;
                return false;
            }

            if( vp->val() == HOLE( "_"_sid ) )
            {
                auto type = LowerTypeForRuntime( c, *ValueFromEIR( vp->type() ) );
                if( !type )
                {
                    success = false;
                    return false;
                }

                paramTypes.emplace_back( GetLLVMType( *type ) );







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
            {
                success = false;
                return false;
            }

            if( vp->val() == HOLE( "_"_sid ) )
            {
                auto type = LowerTypeForRuntime( c, *EIRToValue( vp->type() ) );
                if( !type )
                {
                    success = false;
                    return false;
                }

                paramTypes.emplace_back( GetLLVMType( *type ) );
Changes to bs/builtins/types/func/typecheck.cpp.
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
            ValueToEIR( ValuePattern(
                TSID( constant ),
                FuncTypePattern(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto rhsVal = *ValueFromEIR( rhs );

            if( IsBuiltinFunc( rhsVal ) )
            {
                co_yield { rhs, tcc };
                co_return;
            }








|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
            ValueToEIR( ValuePattern(
                TSID( constant ),
                FuncTypePattern(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto rhsVal = *EIRToValue( rhs );

            if( IsBuiltinFunc( rhsVal ) )
            {
                co_yield { rhs, tcc };
                co_return;
            }

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
                    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 };







|


|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;

            auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *EIRToValue( type ) );
            assert( callPat );

            auto rhsVal = *EIRToValue( rhs );
            auto sig = GetFuncSig( rhsVal );

            for( auto&& [s, tcc] : TypeCheck( sig, *callPat, tcc ) )
            {
                if( IsBuiltinFunc( rhsVal ) )
                {
                    co_yield { ValueToEIR( rhsVal ), tcc };
Changes to bs/builtins/types/init.cpp.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        // all types at runtime will have to go through their own specialization
        // or partial specialization of this, since it will have to emit specialized
        // binary runtime code.
        RegisterBuiltinFunc< Intrinsic< Value ( MutRefOfTypeT, ValueOfTypeT ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r, const Value& initVal )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *ValueFromEIR( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), initVal, r.locationId() ) );
            } );

        // Default initialization for ct_int vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *ValueFromEIR( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), ToValue( BigInt() ), r.locationId() ) );
            } );

        // Default initialization for ct_string vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *ValueFromEIR( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), ToValue( ""s ), r.locationId() ) );
            } );
    }
}







|









|









|





23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
        // all types at runtime will have to go through their own specialization
        // or partial specialization of this, since it will have to emit specialized
        // binary runtime code.
        RegisterBuiltinFunc< Intrinsic< Value ( MutRefOfTypeT, ValueOfTypeT ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r, const Value& initVal )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), initVal, r.locationId() ) );
            } );

        // Default initialization for ct_int vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), ToValue( BigInt() ), r.locationId() ) );
            } );

        // Default initialization for ct_string vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), ToValue( ""s ), r.locationId() ) );
            } );
    }
}
Changes to bs/builtins/types/localvar/localvar.cpp.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

        auto index = cfg->getNewTemporaryIndex();

        auto bb = cfg->currentBB();
        if( !bb )
            return PoisonValue();

        Value typeVal = *ValueFromEIR( type );
        if( !typeVal.isType() )
            typeVal = ToType( c, typeVal );

        if( !ParseTypePredicates( c, typeVal ) )
            return PoisonValue();

        LocalVar lv( name, ValueToEIR( typeVal ), index );







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

        auto index = cfg->getNewTemporaryIndex();

        auto bb = cfg->currentBB();
        if( !bb )
            return PoisonValue();

        Value typeVal = *EIRToValue( type );
        if( !typeVal.isType() )
            typeVal = ToType( c, typeVal );

        if( !ParseTypePredicates( c, typeVal ) )
            return PoisonValue();

        LocalVar lv( name, ValueToEIR( typeVal ), index );
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
                SubTerm(),  // locvar
                SubTerm()   // initializer
            )
        );

        auto&& [type, initializer] = *callDecomp;

        if( !ParseTypePredicates( c, *ValueFromEIR( type ) ) )
            return PoisonValue();

        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 = ValueFromEIR( typeTExpr )->locationId();
        LocalVar lv( name, type, index );

        bb->emplace_back( AllocVar( ValueFromEIR( lv.type() )->setLocationId( typeLoc ), index ) );

        DiagnosticsContext dc( 0, "When invoking Initialize." );

        auto initResult = InvokeOverloadSet( c,
            c.env()->extInitialize(),
            MakeTuple( ToValue( lv ).setLocationId( locId ), initVal ) );








|







|


|







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
                SubTerm(),  // locvar
                SubTerm()   // initializer
            )
        );

        auto&& [type, initializer] = *callDecomp;

        if( !ParseTypePredicates( c, *EIRToValue( type ) ) )
            return PoisonValue();

        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 = EIRToValue( typeTExpr )->locationId();
        LocalVar lv( name, type, index );

        bb->emplace_back( AllocVar( EIRToValue( lv.type() )->setLocationId( typeLoc ), index ) );

        DiagnosticsContext dc( 0, "When invoking Initialize." );

        auto initResult = InvokeOverloadSet( c,
            c.env()->extInitialize(),
            MakeTuple( ToValue( lv ).setLocationId( locId ), initVal ) );

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    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 )
    {
        auto t = FromValue< LocalVarType >( *ValueFromEIR( v.type() ) );
        if( !t )
            return nullopt;

        if( !v.isConstant() )
        {
            // This is an abstract local variable value, this may happen when
            // typechecking abstract arguments while resolving function typed parameters







|







255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    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 )
    {
        auto t = FromValue< LocalVarType >( *EIRToValue( v.type() ) );
        if( !t )
            return nullopt;

        if( !v.isConstant() )
        {
            // This is an abstract local variable value, this may happen when
            // typechecking abstract arguments while resolving function typed parameters
Changes to bs/builtins/types/localvar/typecheck.cpp.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                localVarPattern,
                ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                auto lvarType = *FromValue< LocalVarType >( *ValueFromEIR( ValuePatternFromEIR( lhs )->type() ) );

                auto rhsVal = *ValuePatternFromEIR( rhs );
                auto rvarType = *FromValue< LocalVarType >( *ValueFromEIR( rhsVal.type() ) );

                for( auto&& [s, tcc] : Unify( lvarType.type(), rvarType.type(), tcc ) )
                {
                    co_yield { ValueToEIR( Value( ValueToEIR( ToValue( LocalVarType( s ) ) ),
                        rhsVal.val() ).setLocationId( rhsVal.locationId() ) ), tcc };
                }
            } );







|


|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                localVarPattern,
                ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                auto lvarType = *FromValue< LocalVarType >( *EIRToValue( ValuePatternFromEIR( lhs )->type() ) );

                auto rhsVal = *ValuePatternFromEIR( rhs );
                auto rvarType = *FromValue< LocalVarType >( *EIRToValue( rhsVal.type() ) );

                for( auto&& [s, tcc] : Unify( lvarType.type(), rvarType.type(), tcc ) )
                {
                    co_yield { ValueToEIR( Value( ValueToEIR( ToValue( LocalVarType( s ) ) ),
                        rhsVal.val() ).setLocationId( rhsVal.locationId() ) ), tcc };
                }
            } );
Changes to bs/builtins/types/overloadset/helpers.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "builtins/builtins.h"
#include "execute/execute.h"

namespace goose::builtins
{
    ptr< OverloadSet > CreateOverloadSet( Env& env, const StringId& name )
    {
        auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );
        auto pOvlSet = make_shared< OverloadSet >( identity );
        env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
        return pOvlSet;
    }

    ptr< OverloadSet > GetOverloadSet( Env& env, const StringId& name )
    {
        auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );

        Term result;

        switch( env.retrieveValue( identity, RootIdentity(), result ) )
        {
            case sema::Env::Status::Success:
                return *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );

            case sema::Env::Status::NoMatch:
                G_ERROR( format( "fatal: overload set {} not found", name ) );

            case sema::Env::Status::AmbiguousMatch:
                G_ERROR( format( "fatal: ambiguous match for overload set {}", name ) );
        }

        return nullptr;
    }

    ptr< OverloadSet > GetOrCreateOverloadSet( Env& env, const StringId& name )
    {
        auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );

        Term result;

        switch( env.retrieveValue( identity, RootIdentity(), result ) )
        {
            case sema::Env::Status::Success:
                return *FromValue< ptr< OverloadSet > >( *ValueFromEIR( result ) );

            case sema::Env::Status::NoMatch:
            {
                auto pOvlSet = make_shared< OverloadSet >( identity );
                env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
                return pOvlSet;
            }







|







|



|


|













|



|


|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "builtins/builtins.h"
#include "execute/execute.h"

namespace goose::builtins
{
    ptr< OverloadSet > CreateOverloadSet( Env& env, const StringId& name )
    {
        auto identity = AppendToVectorTerm( RootG0Identity(), TERM( name ) );
        auto pOvlSet = make_shared< OverloadSet >( identity );
        env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
        return pOvlSet;
    }

    ptr< OverloadSet > GetOverloadSet( Env& env, const StringId& name )
    {
        auto identity = AppendToVectorTerm( RootG0Identity(), TERM( name ) );

        Term result;

        switch( env.retrieveValue( identity, RootG0Identity(), result ) )
        {
            case sema::Env::Status::Success:
                return *FromValue< ptr< OverloadSet > >( *EIRToValue( result ) );

            case sema::Env::Status::NoMatch:
                G_ERROR( format( "fatal: overload set {} not found", name ) );

            case sema::Env::Status::AmbiguousMatch:
                G_ERROR( format( "fatal: ambiguous match for overload set {}", name ) );
        }

        return nullptr;
    }

    ptr< OverloadSet > GetOrCreateOverloadSet( Env& env, const StringId& name )
    {
        auto identity = AppendToVectorTerm( RootG0Identity(), TERM( name ) );

        Term result;

        switch( env.retrieveValue( identity, RootG0Identity(), result ) )
        {
            case sema::Env::Status::Success:
                return *FromValue< ptr< OverloadSet > >( *EIRToValue( result ) );

            case sema::Env::Status::NoMatch:
            {
                auto pOvlSet = make_shared< OverloadSet >( identity );
                env.storeValue( identity, ANYTERM( _ ), ValueToEIR( ToValue( pOvlSet ) ) );
                return pOvlSet;
            }
Changes to bs/builtins/types/overloadset/typecheck.cpp.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildCallPatternFromFuncType( *ValueFromEIR( type ) );

            auto rhsVal = *ValueFromEIR( rhs );
            auto os = *FromValue< ptr< OverloadSet > >( rhsVal );

            auto rhsLocId = rhsVal.locationId();

            // Create a new named hole namespace to isolate holes from the passed function from those in
            // the called function.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();







|

|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildCallPatternFromFuncType( *EIRToValue( type ) );

            auto rhsVal = *EIRToValue( rhs );
            auto os = *FromValue< ptr< OverloadSet > >( rhsVal );

            auto rhsLocId = rhsVal.locationId();

            // Create a new named hole namespace to isolate holes from the passed function from those in
            // the called function.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
                    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 os = *FromValue< ptr< OverloadSet > >( rhsVal );

            auto rhsLocId = rhsVal.locationId();

            // Create a new named hole namespace to isolate holes from the called functions from those
            // in the call expression.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();







|


|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *EIRToValue( type ) );
            assert( callPat );

            auto rhsVal = *EIRToValue( rhs );
            auto os = *FromValue< ptr< OverloadSet > >( rhsVal );

            auto rhsLocId = rhsVal.locationId();

            // Create a new named hole namespace to isolate holes from the called functions from those
            // in the call expression.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
Changes to bs/builtins/types/param.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef GOOSE_BUILTINS_TYPES_PARAM_H
#define GOOSE_BUILTINS_TYPES_PARAM_H

namespace goose::builtins
{
    template< typename T, typename V >
    auto ParamPat( T&& type, V&& val )
    {
        // If the type is a tuple of type, convert it to the type of a tuple.
        // (the type of a tuple is just a list of values, so just extract the value part of the tuple)
        if( auto typeVal = ValueFromEIR( type ); typeVal && IsTuple( *typeVal ) )
            return ValueToEIR( Value( ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );

        return ValueToEIR( Value( forward< T >( type ), forward< V >( val ) ) );
    }

    template< typename T >
    auto ParamPat( T&& type )
    {
        // If the type is a tuple of type, convert it to the type of a tuple.
        // (the type of a tuple is just a list of values, so just extract the value part of the tuple)
        if( auto typeVal = ValueFromEIR( type ); typeVal && IsTuple( *typeVal ) )
            return ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );

        return ValueToEIR( ValuePattern( TSID( param ), forward< T >( type ), HOLE( "_"_sid ) ) );
    }

    // This special param pattern forces the argument to be passed as it without any typechecking.
    struct ForwarderPattern










|










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef GOOSE_BUILTINS_TYPES_PARAM_H
#define GOOSE_BUILTINS_TYPES_PARAM_H

namespace goose::builtins
{
    template< typename T, typename V >
    auto ParamPat( T&& type, V&& val )
    {
        // If the type is a tuple of type, convert it to the type of a tuple.
        // (the type of a tuple is just a list of values, so just extract the value part of the tuple)
        if( auto typeVal = EIRToValue( type ); typeVal && IsTuple( *typeVal ) )
            return ValueToEIR( Value( ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );

        return ValueToEIR( Value( forward< T >( type ), forward< V >( val ) ) );
    }

    template< typename T >
    auto ParamPat( T&& type )
    {
        // If the type is a tuple of type, convert it to the type of a tuple.
        // (the type of a tuple is just a list of values, so just extract the value part of the tuple)
        if( auto typeVal = EIRToValue( type ); typeVal && IsTuple( *typeVal ) )
            return ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );

        return ValueToEIR( ValuePattern( TSID( param ), forward< T >( type ), HOLE( "_"_sid ) ) );
    }

    // This special param pattern forces the argument to be passed as it without any typechecking.
    struct ForwarderPattern
Changes to bs/builtins/types/pretty.cpp.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
        auto& pp = PrettyPrinter::GetInstance();

        pp.addRule( TypeType(), [&]( auto&& out, auto&& t ) { out << "TypeType"; return true; } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ), ANYTERM(_), ANYTERM(_) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto v = *ValueFromEIR( t );
                auto ty = ValueFromEIR( v.type() );
                out << "constant[ ";
                pp.print( out, ty ? ty->val() : v.type() );
                out << " ]{ ";
                pp.print( out, v.val() );
                out << " }";
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ), TypeType(), ANYTERM(_) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto v = *ValueFromEIR( t );
                out << "type[ ";
                pp.print( out, v.val() );
                out << " ]";
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( computed ), ANYTERM(_), ANYTERM(_) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto v = *ValueFromEIR( t );
                auto ty = ValueFromEIR( v.type() );
                out << "value[ ";
                pp.print( out, ty ? ty->val() : v.type() );
                out << " ]";
                if( v.cir() )
                    out << "{ " << *v.cir() << " }";
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), VEC( TSID( decl ), ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto decl = *FromValue< Decl >( *ValueFromEIR( t ) );
                out << "decl(" << decl.type() << ", " << decl.name() << ")";
                return true;
            } );

        pp.addRule( GetValueType< bool >(), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );
        pp.addRule( MkStdType( TSID( bool ) ), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );








|
|











|









|
|













|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
        auto& pp = PrettyPrinter::GetInstance();

        pp.addRule( TypeType(), [&]( auto&& out, auto&& t ) { out << "TypeType"; return true; } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ), ANYTERM(_), ANYTERM(_) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto v = *EIRToValue( t );
                auto ty = EIRToValue( v.type() );
                out << "constant[ ";
                pp.print( out, ty ? ty->val() : v.type() );
                out << " ]{ ";
                pp.print( out, v.val() );
                out << " }";
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ), TypeType(), ANYTERM(_) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto v = *EIRToValue( t );
                out << "type[ ";
                pp.print( out, v.val() );
                out << " ]";
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( computed ), ANYTERM(_), ANYTERM(_) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto v = *EIRToValue( t );
                auto ty = EIRToValue( v.type() );
                out << "value[ ";
                pp.print( out, ty ? ty->val() : v.type() );
                out << " ]";
                if( v.cir() )
                    out << "{ " << *v.cir() << " }";
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), VEC( TSID( decl ), ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto decl = *FromValue< Decl >( *EIRToValue( t ) );
                out << "decl(" << decl.type() << ", " << decl.name() << ")";
                return true;
            } );

        pp.addRule( GetValueType< bool >(), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );
        pp.addRule( MkStdType( TSID( bool ) ), [&]( auto&& out, auto&& t ) { out << "bool"; return true; } );

Changes to bs/builtins/types/reference/init.cpp.
10
11
12
13
14
15
16
17
18
19
20
21
22
    {
        RegisterBuiltinFunc< Intrinsic< Value ( CustomPattern< Value,
            ReferenceType::PatternMutableOf< ReferenceType::PatternXOfTypeT > >,
            CustomPattern< Value, ReferenceType::PatternXOfTypeT > ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r, const Value& initVal )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *ValueFromEIR( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), initVal, r.locationId() ) );
            } );
    }
}







|





10
11
12
13
14
15
16
17
18
19
20
21
22
    {
        RegisterBuiltinFunc< Intrinsic< Value ( CustomPattern< Value,
            ReferenceType::PatternMutableOf< ReferenceType::PatternXOfTypeT > >,
            CustomPattern< Value, ReferenceType::PatternXOfTypeT > ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r, const Value& initVal )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), initVal, r.locationId() ) );
            } );
    }
}
Changes to bs/builtins/types/reference/lower.cpp.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    void SetupReferenceLowering( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< Value, ReferenceType::PatternAny > ) > >( e, e.extLowerTypeForRuntime(),
            []( const Context& c, const Value& refType )
        {
            auto rt = *FromValue< ReferenceType >( refType );

            auto loweredType = LowerTypeForRuntime( c, *ValueFromEIR( rt.type() ) );
            if( !loweredType || loweredType->isPoison() )
                return PoisonValue();

            return ToValue( PointerType( ValueToEIR( *loweredType ) ) );
        } );
    }
}







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    void SetupReferenceLowering( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< Value, ReferenceType::PatternAny > ) > >( e, e.extLowerTypeForRuntime(),
            []( const Context& c, const Value& refType )
        {
            auto rt = *FromValue< ReferenceType >( refType );

            auto loweredType = LowerTypeForRuntime( c, *EIRToValue( rt.type() ) );
            if( !loweredType || loweredType->isPoison() )
                return PoisonValue();

            return ToValue( PointerType( ValueToEIR( *loweredType ) ) );
        } );
    }
}
Changes to bs/builtins/types/reference/parse.cpp.
1
2
3

4
5
6
7
8
9
10
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"


using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{



>







1
2
3
4
5
6
7
8
9
10
11
#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::parse;

namespace goose::builtins
{
54
55
56
57
58
59
60
61
62
63
64
65
66
            auto loc = Location::CreateSpanningLocation( locationId, type->locationId() );

            ReferenceType rt( ValueToEIR( *type ), move( bhv ) );
            p.pushValue( ToDeclValue( rt ).setLocationId( loc ) );
            return true;
        };

        Rule r( parseRefType );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ref ) ), ANYTERM( _ ), ruleTerm );
    }
}







|
<
<
<


55
56
57
58
59
60
61
62



63
64
            auto loc = Location::CreateSpanningLocation( locationId, type->locationId() );

            ReferenceType rt( ValueToEIR( *type ), move( bhv ) );
            p.pushValue( ToDeclValue( rt ).setLocationId( loc ) );
            return true;
        };

        RegisterRule( e, "ref"_sid, Rule( parseRefType ) );



    }
}
Changes to bs/builtins/types/reference/reference.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    bool IsReferenceType( const Term& t )
    {
        auto result = Decompose( ValueFromEIR( t )->val(),
            Vec(
                Lit( "reference"_sid ),
                SubTerm(),
                SubTerm()
            )
        );












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::builtins;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    bool IsReferenceType( const Term& t )
    {
        auto result = Decompose( EIRToValue( t )->val(),
            Vec(
                Lit( "reference"_sid ),
                SubTerm(),
                SubTerm()
            )
        );

Changes to bs/builtins/types/reference/typecheck.cpp.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    using namespace goose::builtins;

    auto refTypePattern = ValueToEIR(
        Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

    TCGen TypeCheckingDereference( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
    {
        auto refval = ValueFromEIR( rhs );
        if( !refval )
            co_return;

        auto refType = FromValue< ReferenceType >( *ValueFromEIR( refval->type() ) );
        if( !refType )
            co_return;

        auto content = ValueToEIR( BuildComputedValue( refType->type(),
            cir::Load( refval->cir(), refType->type() ) )
            .setLocationId( refval->locationId() ) );

        // TypeCheck the param with the ref's content
        co_yield TypeCheck( lhs, content, tcc );
    }

    TCGen TypeCheckingBuildTempRef( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc )
    {
        if( !tcc.context().codeBuilder() )
            co_return;

        if( !tcc.context().codeBuilder()->cfg() )
            co_return;

        auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromEIR( lhs )->type() ) );

        if( lRefType.behavior() == TSID( mut ) )
            co_return;

        auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );

        for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )







|



|



















|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    using namespace goose::builtins;

    auto refTypePattern = ValueToEIR(
        Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

    TCGen TypeCheckingDereference( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
    {
        auto refval = EIRToValue( rhs );
        if( !refval )
            co_return;

        auto refType = FromValue< ReferenceType >( *EIRToValue( refval->type() ) );
        if( !refType )
            co_return;

        auto content = ValueToEIR( BuildComputedValue( refType->type(),
            cir::Load( refval->cir(), refType->type() ) )
            .setLocationId( refval->locationId() ) );

        // TypeCheck the param with the ref's content
        co_yield TypeCheck( lhs, content, tcc );
    }

    TCGen TypeCheckingBuildTempRef( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc )
    {
        if( !tcc.context().codeBuilder() )
            co_return;

        if( !tcc.context().codeBuilder()->cfg() )
            co_return;

        auto lRefType = *FromValue< ReferenceType >( *EIRToValue( ValuePatternFromEIR( lhs )->type() ) );

        if( lRefType.behavior() == TSID( mut ) )
            co_return;

        auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );

        for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
                            SubTerm()
                        )
                    );

                    assert( result );
                    auto&& [ref, rhs] = *result;

                    auto rhsVal = *ValueFromEIR( rhs );
                    auto refPat = *ValuePatternFromEIR( ref );

                    auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
                    return ValueToEIR( BuildComputedValue( refPat.type(), TempAddr( tempIndex, rhsVal ) )
                        .setLocationId( rhsVal.locationId() ) );
                } );








|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
                            SubTerm()
                        )
                    );

                    assert( result );
                    auto&& [ref, rhs] = *result;

                    auto rhsVal = *EIRToValue( rhs );
                    auto refPat = *ValuePatternFromEIR( ref );

                    auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
                    return ValueToEIR( BuildComputedValue( refPat.type(), TempAddr( tempIndex, rhsVal ) )
                        .setLocationId( rhsVal.locationId() ) );
                } );

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromEIR( lhs )->type() ) );

                auto rhsVal = *ValuePatternFromEIR( rhs );
                auto rRefType = *FromValue< ReferenceType >( *ValueFromEIR( rhsVal.type() ) );

                // Type check the behaviors
                for( auto&& [b, tcc] : TypeCheck( lRefType.behavior(), rRefType.behavior(), tcc ) )
                {
                    // Check the types
                    for( auto&& [t, tcc] : TypeCheck( lRefType.type(), rRefType.type(), tcc ) )
                    {







|


|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                auto lRefType = *FromValue< ReferenceType >( *EIRToValue( ValuePatternFromEIR( lhs )->type() ) );

                auto rhsVal = *ValuePatternFromEIR( rhs );
                auto rRefType = *FromValue< ReferenceType >( *EIRToValue( rhsVal.type() ) );

                // Type check the behaviors
                for( auto&& [b, tcc] : TypeCheck( lRefType.behavior(), rRefType.behavior(), tcc ) )
                {
                    // Check the types
                    for( auto&& [t, tcc] : TypeCheck( lRefType.type(), rRefType.type(), tcc ) )
                    {
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
                localVarPattern,
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltype = ValuePatternFromEIR( lhs )->type();

            auto lvval = *ValueFromEIR( rhs );
            auto locvar = FromValue< LocalVar >( lvval );
            if( !locvar )
                co_return;

            auto ref = ValueToEIR( ToValue( BuildLocalVarMutRef( *locvar ) )
                .setLocationId( lvval.locationId() ) );








|







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
                localVarPattern,
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltype = ValuePatternFromEIR( lhs )->type();

            auto lvval = *EIRToValue( rhs );
            auto locvar = FromValue< LocalVar >( lvval );
            if( !locvar )
                co_return;

            auto ref = ValueToEIR( ToValue( BuildLocalVarMutRef( *locvar ) )
                .setLocationId( lvval.locationId() ) );

Changes to bs/builtins/types/runtime/array.cpp.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

                return ToValue( ArrayType( ValueToEIR( containedType ), count ) );
            } );
    }

    llvm::Type* GetLLVMType( const ArrayType& a )
    {
        return llvm::ArrayType::get( GetLLVMType( *ValueFromEIR( a.m_containedType ) ), a.m_count );
    }
}

namespace goose::eir
{
    Value Bridge< ArrayType >::ToValue( const ArrayType& a )
    {







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

                return ToValue( ArrayType( ValueToEIR( containedType ), count ) );
            } );
    }

    llvm::Type* GetLLVMType( const ArrayType& a )
    {
        return llvm::ArrayType::get( GetLLVMType( *EIRToValue( a.m_containedType ) ), a.m_count );
    }
}

namespace goose::eir
{
    Value Bridge< ArrayType >::ToValue( const ArrayType& a )
    {
Changes to bs/builtins/types/runtime/basic.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "builtins/builtins.h"
#include "codegen/codegen.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;

namespace goose::builtins
{
    void SetupRuntimeBasicTypes( Env& e )
    {
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( half ) ), ANYTERM( _ ), ValueToEIR( ToValue( HalfFloatType() ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( float ) ), ANYTERM( _ ), ValueToEIR( ToValue( FloatType() ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( double ) ), ANYTERM( _ ), ValueToEIR( ToValue( DoubleFloatType() ) ) );

        RegisterBuiltinFunc< Eager< Value > ( uint32_t ) >( e, "uint"_sid,
            []( uint32_t numBits )
            {
                return ToValue( IntegerType( numBits ) );
            } );













|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "builtins/builtins.h"
#include "codegen/codegen.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::builtins;
using namespace goose::codegen;

namespace goose::builtins
{
    void SetupRuntimeBasicTypes( Env& e )
    {
        DefineConstant( e, "half"_sid, ValueToEIR( ToValue( HalfFloatType() ) ) );
        DefineConstant( e, "float"_sid, ValueToEIR( ToValue( FloatType() ) ) );
        DefineConstant( e, "double"_sid, ValueToEIR( ToValue( DoubleFloatType() ) ) );

        RegisterBuiltinFunc< Eager< Value > ( uint32_t ) >( e, "uint"_sid,
            []( uint32_t numBits )
            {
                return ToValue( IntegerType( numBits ) );
            } );

Changes to bs/builtins/types/runtime/init.cpp.
14
15
16
17
18
19
20
21
22
23
24
25
26
        using IntegerType = CustomPattern< IntegerType, IntegerType::Pattern >;

        // Initialization for integer vars
        RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType, IntegerType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r, const Value& initVal )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *ValueFromEIR( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), initVal, r.locationId() ) );
            } );
    }
}







|





14
15
16
17
18
19
20
21
22
23
24
25
26
        using IntegerType = CustomPattern< IntegerType, IntegerType::Pattern >;

        // Initialization for integer vars
        RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType, IntegerType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r, const Value& initVal )
            {
                G_VAL_ASSERT( r, !r.isConstant() );
                auto refType = *FromValue< ReferenceType >( *EIRToValue( r.type() ) );
                return BuildComputedValue( GetValueType< void >(),
                    Store( r.cir(), refType.type(), initVal, r.locationId() ) );
            } );
    }
}
Changes to bs/builtins/types/runtime/pointer.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::builtins;

namespace goose::builtins
{
    void SetupRuntimePointerType( Env& e )
    {
        // null pointer literal
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( nullptr ) ), ANYTERM( _ ), ValueToEIR( ToValue( NullPointer() ) ) );

        RegisterBuiltinFunc< Eager< Value > ( Value ) >( e, "pointer"_sid,
            []( const Value& pointedType )
            {
                if( !GetLLVMType( pointedType ) )
                {
                    // TODO come up with some lightweight builtin option type
                    // for the builtin apis, because this is a very bullshit
                    // way to handle errors
                    return ToValue( "error"s );
                }

                return ToValue( PointerType( ValueToEIR( pointedType ) ) );
            } );
    }

    llvm::Type* GetLLVMType( const PointerType& p )
    {
        return llvm::PointerType::getUnqual( GetLLVMType( *ValueFromEIR( p.m_pointedType ) ) );
    }
}

namespace goose::eir
{
    Value Bridge< PointerType >::ToValue( const PointerType& p )
    {











|


















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "builtins/builtins.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::builtins;

namespace goose::builtins
{
    void SetupRuntimePointerType( Env& e )
    {
        // null pointer literal
        e.storeValue( AppendToVectorTerm( RootG0Identity(), TSID( nullptr ) ), ANYTERM( _ ), ValueToEIR( ToValue( NullPointer() ) ) );

        RegisterBuiltinFunc< Eager< Value > ( Value ) >( e, "pointer"_sid,
            []( const Value& pointedType )
            {
                if( !GetLLVMType( pointedType ) )
                {
                    // TODO come up with some lightweight builtin option type
                    // for the builtin apis, because this is a very bullshit
                    // way to handle errors
                    return ToValue( "error"s );
                }

                return ToValue( PointerType( ValueToEIR( pointedType ) ) );
            } );
    }

    llvm::Type* GetLLVMType( const PointerType& p )
    {
        return llvm::PointerType::getUnqual( GetLLVMType( *EIRToValue( p.m_pointedType ) ) );
    }
}

namespace goose::eir
{
    Value Bridge< PointerType >::ToValue( const PointerType& p )
    {
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    {
        static auto val = Value( Type(), TSID( nullptr ) );
        return val;
    }

    optional< NullPointer > Bridge< NullPointer >::FromValue( const Value& v )
    {
        if( !FromValue< NullPointerType >( *ValueFromEIR( v.type() ) ) )
            return nullopt;

        auto result = Decompose( v.val(),
            Lit( "nullptr"_sid )
        );

        if( !result )
            return nullopt;

        return NullPointer();
    }
}







|












87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    {
        static auto val = Value( Type(), TSID( nullptr ) );
        return val;
    }

    optional< NullPointer > Bridge< NullPointer >::FromValue( const Value& v )
    {
        if( !FromValue< NullPointerType >( *EIRToValue( v.type() ) ) )
            return nullopt;

        auto result = Decompose( v.val(),
            Lit( "nullptr"_sid )
        );

        if( !result )
            return nullopt;

        return NullPointer();
    }
}
Changes to bs/builtins/types/runtime/record.cpp.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    llvm::Type* GetLLVMType( const RecordType& rt )
    {
        vector< llvm::Type* > elements;
        elements.reserve( rt.m_memberTypes->terms().size() );

        for( auto&& mt : rt.m_memberTypes->terms() )
        {
            auto llvmType = GetLLVMType( *ValueFromEIR( mt ) );
            assert( llvmType );
            elements.emplace_back( llvmType );
        }

        return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
    }
}







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    llvm::Type* GetLLVMType( const RecordType& rt )
    {
        vector< llvm::Type* > elements;
        elements.reserve( rt.m_memberTypes->terms().size() );

        for( auto&& mt : rt.m_memberTypes->terms() )
        {
            auto llvmType = GetLLVMType( *EIRToValue( mt ) );
            assert( llvmType );
            elements.emplace_back( llvmType );
        }

        return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
    }
}
Changes to bs/builtins/types/runtime/typecheck.cpp.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            // The rhs might not be constant. It can happen even with ct_int if the rhs is a
            // fake argument pattern generated to unify a higher-order function param.
            // It means that we are unifying a function parameter against any ct_int value,
            // which we can't (because we have to know the value to safely convert it),
            // so we reject it.
            auto rhsVal = *ValueFromEIR( rhs );
            if( !rhsVal.isConstant() )
                co_return;

            auto lhsVal = ValuePatternFromEIR( lhs );
            if( !lhsVal )
                co_return;

            auto s = HalfUnify( lhsVal->type(), tcc );
            if( !s )
                co_return;

            auto wrapped = WrapWithPostprocFunc( *s,
            [rhs]( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
            {
                auto argVal = ValueFromEIR( rhs );
                assert( argVal );

                auto ct = *FromValue< BigInt >( *argVal );

                auto rttypeVal = ValueFromEIR( t );
                assert( rttypeVal );

                auto rttype = FromValue< IntegerType >( *rttypeVal );
                assert( rttype );

                APSInt valToLoad;








|














|




|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            // The rhs might not be constant. It can happen even with ct_int if the rhs is a
            // fake argument pattern generated to unify a higher-order function param.
            // It means that we are unifying a function parameter against any ct_int value,
            // which we can't (because we have to know the value to safely convert it),
            // so we reject it.
            auto rhsVal = *EIRToValue( rhs );
            if( !rhsVal.isConstant() )
                co_return;

            auto lhsVal = ValuePatternFromEIR( lhs );
            if( !lhsVal )
                co_return;

            auto s = HalfUnify( lhsVal->type(), tcc );
            if( !s )
                co_return;

            auto wrapped = WrapWithPostprocFunc( *s,
            [rhs]( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
            {
                auto argVal = EIRToValue( rhs );
                assert( argVal );

                auto ct = *FromValue< BigInt >( *argVal );

                auto rttypeVal = EIRToValue( t );
                assert( rttypeVal );

                auto rttype = FromValue< IntegerType >( *rttypeVal );
                assert( rttype );

                APSInt valToLoad;

Changes to bs/builtins/types/template/build.cpp.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    {
        auto v = make_shared< Vector >();
        v->reserve( VecSize( tft.params() ) + 1 );

        auto rtSig = BuildTemplateSignature( c, tft.returnType() );
        if( !rtSig )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( tft.returnType() )->locationId(),
                "Invalid template return type or texpr." );
            return nullopt;
        }
        v->append( move( *rtSig ) );

        bool success = true;
        ForEachInVectorTerm( tft.params(), [&]( auto&& param )
        {
            auto teSig = BuildTemplateSignature( c, param );
            if( !teSig )
            {
                DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( param )->locationId(),
                    "Invalid template parameter." );
                success = false;
                return false;
            }

            v->append( move( *teSig ) );
            return true;







|











|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    {
        auto v = make_shared< Vector >();
        v->reserve( VecSize( tft.params() ) + 1 );

        auto rtSig = BuildTemplateSignature( c, tft.returnType() );
        if( !rtSig )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( EIRToValue( tft.returnType() )->locationId(),
                "Invalid template return type or texpr." );
            return nullopt;
        }
        v->append( move( *rtSig ) );

        bool success = true;
        ForEachInVectorTerm( tft.params(), [&]( auto&& param )
        {
            auto teSig = BuildTemplateSignature( c, param );
            if( !teSig )
            {
                DiagnosticsManager::GetInstance().emitErrorMessage( EIRToValue( param )->locationId(),
                    "Invalid template parameter." );
                success = false;
                return false;
            }

            v->append( move( *teSig ) );
            return true;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

        auto apv = make_shared< Vector >();
        apv->reserve( VecSize( ftype->params() ) + 1 );

        auto rtArgPat = BuildTemplateArgPattern( c, ftype->returnType() );
        if( !rtArgPat )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( ftype->returnType() )->locationId(),
                "Invalid template return type or texpr." );
            return nullopt;
        }
        apv->append( move( *rtArgPat ) );

        bool success = true;
        ForEachInVectorTerm( ftype->params(), [&]( auto&& param )
        {
            auto teArgPat = BuildTemplateArgPattern( c, param );
            if( !teArgPat )
            {
                DiagnosticsManager::GetInstance().emitErrorMessage( ValueFromEIR( param )->locationId(),
                    "Invalid template parameter." );
                success = false;
                return false;
            }

            apv->append( move( *teArgPat ) );
            return true;







|











|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

        auto apv = make_shared< Vector >();
        apv->reserve( VecSize( ftype->params() ) + 1 );

        auto rtArgPat = BuildTemplateArgPattern( c, ftype->returnType() );
        if( !rtArgPat )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( EIRToValue( ftype->returnType() )->locationId(),
                "Invalid template return type or texpr." );
            return nullopt;
        }
        apv->append( move( *rtArgPat ) );

        bool success = true;
        ForEachInVectorTerm( ftype->params(), [&]( auto&& param )
        {
            auto teArgPat = BuildTemplateArgPattern( c, param );
            if( !teArgPat )
            {
                DiagnosticsManager::GetInstance().emitErrorMessage( EIRToValue( param )->locationId(),
                    "Invalid template parameter." );
                success = false;
                return false;
            }

            apv->append( move( *teArgPat ) );
            return true;
Changes to bs/builtins/types/template/instantiate.cpp.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
            {
                auto p = BuildTemplateParam( c, param, arg );
                instanceParams = AppendToTuple( instanceParams, p );
                return true;
            } );

        // Build the instance function type and identity
        auto returnType = *ValueFromEIR( unifiedRType );

        auto instanceType = BuildFuncType( c, returnType, instanceParams );
        if( !instanceType )
            return PoisonValue();

        instanceType->setIntrinsic( tf->type().intrinsic() );

        auto instanceSig = GetFuncSigFromType( ToValue( *instanceType ) );
        auto instanceIdentity = AppendToVectorTerm( tf->identity(), instanceSig );

        // Look for an already existing instanced function
        Value instanceFunc = PoisonValue();

        Term result;
        switch( c.env()->retrieveValue( instanceIdentity, c.identity(), result ) )
        {
            case Env::Status::Success:
                instanceFunc = *ValueFromEIR( result );
                break;

            case Env::Status::NoMatch:
            {
                // Prepare the verification statements
                instanceType->verifInfos()->setPreCondToks( tf->type().preCondToks() );
                instanceType->verifInfos()->setPostCondToks( tf->type().postCondToks() );







|

















|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
            {
                auto p = BuildTemplateParam( c, param, arg );
                instanceParams = AppendToTuple( instanceParams, p );
                return true;
            } );

        // Build the instance function type and identity
        auto returnType = *EIRToValue( unifiedRType );

        auto instanceType = BuildFuncType( c, returnType, instanceParams );
        if( !instanceType )
            return PoisonValue();

        instanceType->setIntrinsic( tf->type().intrinsic() );

        auto instanceSig = GetFuncSigFromType( ToValue( *instanceType ) );
        auto instanceIdentity = AppendToVectorTerm( tf->identity(), instanceSig );

        // Look for an already existing instanced function
        Value instanceFunc = PoisonValue();

        Term result;
        switch( c.env()->retrieveValue( instanceIdentity, c.identity(), result ) )
        {
            case Env::Status::Success:
                instanceFunc = *EIRToValue( result );
                break;

            case Env::Status::NoMatch:
            {
                // Prepare the verification statements
                instanceType->verifInfos()->setPreCondToks( tf->type().preCondToks() );
                instanceType->verifInfos()->setPostCondToks( tf->type().postCondToks() );
Changes to bs/builtins/types/template/pretty.cpp.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
        auto& pp = PrettyPrinter::GetInstance();

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) ),
                ANYTERM( _ ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto tvar = *FromValue< TVar >( *ValueFromEIR( t ) );
                out << '$' << tvar.name();
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( ttvar ) ) ) ),
                ANYTERM( _ ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto tvar = *FromValue< TTVar >( *ValueFromEIR( t ) );
                out << "$$" << tvar.name();
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), TSID( tnameddecl ) ) ),
                VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto decl = *FromValue< TNamedDecl >( *ValueFromEIR( t ) );
                out << "tnameddecl(" << decl.type() << ", " << decl.name() << ")";
                return true;
            } );
    }
}







|









|









|





12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
        auto& pp = PrettyPrinter::GetInstance();

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) ),
                ANYTERM( _ ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto tvar = *FromValue< TVar >( *EIRToValue( t ) );
                out << '$' << tvar.name();
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( ttvar ) ) ) ),
                ANYTERM( _ ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto tvar = *FromValue< TTVar >( *EIRToValue( t ) );
                out << "$$" << tvar.name();
                return true;
            } );

        pp.addRule( ValueToEIR( ValuePattern( TSID( constant ),
            ValueToEIR( Value( TypeType(), TSID( tnameddecl ) ) ),
                VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) ),
            [&]( auto&& out, auto&& t )
            {
                auto decl = *FromValue< TNamedDecl >( *EIRToValue( t ) );
                out << "tnameddecl(" << decl.type() << ", " << decl.name() << ")";
                return true;
            } );
    }
}
Changes to bs/builtins/types/template/rules.cpp.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        tcc.eraseLHSName( name );
    }

    class DeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto decl = FromValue< Decl >( *ValueFromEIR( val ) );
            assert( decl );
            return ParamPat( decl->type() );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *ValueFromEIR( param );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            auto decl = FromValue< Decl >( *ValueFromEIR( val ) );
            assert( decl );
            return ValueToEIR( ValuePattern( TSID( computed ), decl->type(), TERM( ptr< void >() ) ) );
        }
    };

    class TNamedDeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *ValueFromEIR( val ) );
            assert( tnd );

            auto typeSig = BuildTemplateSignature( c, tnd->type() );
            if( !typeSig )
                return nullopt;

            return ParamPat( *typeSig );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& argEIR ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *ValueFromEIR( param ) );
            assert( tnd );

            auto arg = *ValueFromEIR( argEIR );
            return ToValue( Decl( arg.type(), tnd->name() ) );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *ValueFromEIR( val ) );
            assert( tnd );
            TemplateSetup( c, tcc, tnd->type() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *ValueFromEIR( val ) );
            assert( tnd );

            auto typeSig = BuildTemplateArgPattern( c, tnd->type() );
            if( !typeSig )
                return nullopt;

            return ValueToEIR( ValuePattern( TSID( computed ), *typeSig, TERM( ptr< void >() ) ) );
        }
    };

    class TDeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            return val;
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *ValueFromEIR( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tdecl = FromValue< TDecl >( *ValueFromEIR( val ) );
            assert( tdecl );

            TemplateSetup( c, tcc, tdecl->type() );
            setupTVar( c, tcc, tdecl->name() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
        }
    };

    class TVarTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto tvar = FromValue< TVar >( *ValueFromEIR( val ) );
            assert( tvar );
            return HOLE( tvar->name(), TSID( tvar ) );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *ValueFromEIR( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tvar = FromValue< TVar >( *ValueFromEIR( val ) );
            assert( tvar );
            setupTVar( c, tcc, tvar->name() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
        }
    };

    class TTVarTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto ttvar = FromValue< TTVar >( *ValueFromEIR( val ) );
            assert( ttvar );
            return HOLE( ttvar->name(), TSID( fwd ) );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *ValueFromEIR( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto ttvar = FromValue< TTVar >( *ValueFromEIR( val ) );
            assert( ttvar );
            setupTVar( c, tcc, ttvar->name() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );







|






|




|









|











|


|





|






|



















|




|
















|






|




|














|






|




|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
        tcc.eraseLHSName( name );
    }

    class DeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto decl = FromValue< Decl >( *EIRToValue( val ) );
            assert( decl );
            return ParamPat( decl->type() );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *EIRToValue( param );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            auto decl = FromValue< Decl >( *EIRToValue( val ) );
            assert( decl );
            return ValueToEIR( ValuePattern( TSID( computed ), decl->type(), TERM( ptr< void >() ) ) );
        }
    };

    class TNamedDeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *EIRToValue( val ) );
            assert( tnd );

            auto typeSig = BuildTemplateSignature( c, tnd->type() );
            if( !typeSig )
                return nullopt;

            return ParamPat( *typeSig );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& argEIR ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *EIRToValue( param ) );
            assert( tnd );

            auto arg = *EIRToValue( argEIR );
            return ToValue( Decl( arg.type(), tnd->name() ) );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *EIRToValue( val ) );
            assert( tnd );
            TemplateSetup( c, tcc, tnd->type() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            auto tnd = FromValue< TNamedDecl >( *EIRToValue( val ) );
            assert( tnd );

            auto typeSig = BuildTemplateArgPattern( c, tnd->type() );
            if( !typeSig )
                return nullopt;

            return ValueToEIR( ValuePattern( TSID( computed ), *typeSig, TERM( ptr< void >() ) ) );
        }
    };

    class TDeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            return val;
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *EIRToValue( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tdecl = FromValue< TDecl >( *EIRToValue( val ) );
            assert( tdecl );

            TemplateSetup( c, tcc, tdecl->type() );
            setupTVar( c, tcc, tdecl->name() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
        }
    };

    class TVarTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto tvar = FromValue< TVar >( *EIRToValue( val ) );
            assert( tvar );
            return HOLE( tvar->name(), TSID( tvar ) );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *EIRToValue( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tvar = FromValue< TVar >( *EIRToValue( val ) );
            assert( tvar );
            setupTVar( c, tcc, tvar->name() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
        }
    };

    class TTVarTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            auto ttvar = FromValue< TTVar >( *EIRToValue( val ) );
            assert( ttvar );
            return HOLE( ttvar->name(), TSID( fwd ) );
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *EIRToValue( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto ttvar = FromValue< TTVar >( *EIRToValue( val ) );
            assert( ttvar );
            setupTVar( c, tcc, ttvar->name() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
            }

            return v;
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *ValueFromEIR( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& t ) const final
        {
            auto tvec = TVecFromEIR( t );
            assert( tvec );








|







201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
            }

            return v;
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *EIRToValue( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& t ) const final
        {
            auto tvec = TVecFromEIR( t );
            assert( tvec );

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
        }
    };

    class ValueTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& valEIR ) const final
        {
            auto val = *ValueFromEIR( valEIR );
            auto vsig = BuildTemplateSignature( c, val.val() );
            if( IsType( c, val ) )
                return ParamPat( val.type(), vsig ? move( *vsig ) : val.val() );

            auto tsig = BuildTemplateSignature( c, val.type() );
            return ParamPat( tsig ? move( *tsig ) : val.type(), vsig ? move( *vsig ) : val.val() );
        }

        Value buildParamDecl( const Context& c, const Term& val, const Term& arg ) const final
        {
            return *ValueFromEIR( val );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& valEIR ) const final
        {
            auto val = *ValueFromEIR( valEIR );
            TemplateSetup( c, tcc, val.type() );
            TemplateSetup( c, tcc, val.val() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
        }
    };

    class TFuncTypeTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            return val;
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *ValueFromEIR( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tft = FromValue< TFuncType >( *ValueFromEIR( val ) );
            assert( tft );

            ForEachInVectorTerm( tft->params(), [&]( auto&& param )
            {
                 TemplateSetup( c, tcc, param );
                 return true;
            } );







|










|




|



















|




|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
        }
    };

    class ValueTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& valEIR ) const final
        {
            auto val = *EIRToValue( valEIR );
            auto vsig = BuildTemplateSignature( c, val.val() );
            if( IsType( c, val ) )
                return ParamPat( val.type(), vsig ? move( *vsig ) : val.val() );

            auto tsig = BuildTemplateSignature( c, val.type() );
            return ParamPat( tsig ? move( *tsig ) : val.type(), vsig ? move( *vsig ) : val.val() );
        }

        Value buildParamDecl( const Context& c, const Term& val, const Term& arg ) const final
        {
            return *EIRToValue( val );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& valEIR ) const final
        {
            auto val = *EIRToValue( valEIR );
            TemplateSetup( c, tcc, val.type() );
            TemplateSetup( c, tcc, val.val() );
        }

        optional< Term > buildArgPattern( const Context& c, const Term& val ) const final
        {
            return buildSignature( c, val );
        }
    };

    class TFuncTypeTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Term& val ) const final
        {
            return val;
        }

        Value buildParamDecl( const Context& c, const Term& param, const Term& arg ) const final
        {
            return *EIRToValue( arg );
        }

        void setup( const Context& c, TypeCheckingContext& tcc, const Term& val ) const final
        {
            auto tft = FromValue< TFuncType >( *EIRToValue( val ) );
            assert( tft );

            ForEachInVectorTerm( tft->params(), [&]( auto&& param )
            {
                 TemplateSetup( c, tcc, param );
                 return true;
            } );
Changes to bs/builtins/types/template/tc-tdecl.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "builtins/builtins.h"

namespace goose::builtins
{
    Term BuildArgPatternFromTDecl( const TDecl& td )
    {
        return ValueToEIR( ValuePattern( HOLE( "_"_sid ), td.type(), HOLE( "_"_sid ) ) );
    }

    TCGen TypeCheckTDecl( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
    {
        auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
        assert( tdecl );

        auto tdeclHole = HOLE( tdecl->name() );

        auto pat = ValueToEIR( Value( tdecl->type(), HOLE( "_"_sid ) ) );

        for( auto&& [s,tcc] : Unify( pat, rhs, tcc ) )











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "builtins/builtins.h"

namespace goose::builtins
{
    Term BuildArgPatternFromTDecl( const TDecl& td )
    {
        return ValueToEIR( ValuePattern( HOLE( "_"_sid ), td.type(), HOLE( "_"_sid ) ) );
    }

    TCGen TypeCheckTDecl( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
    {
        auto tdecl = FromValue< TDecl >( *EIRToValue( lhs ) );
        assert( tdecl );

        auto tdeclHole = HOLE( tdecl->name() );

        auto pat = ValueToEIR( Value( tdecl->type(), HOLE( "_"_sid ) ) );

        for( auto&& [s,tcc] : Unify( pat, rhs, tcc ) )
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    void SetupTDeclTypeChecking( Env& e )
    {
        auto tDeclPat = ValueToEIR( Value( GetValueType< TDecl >(), VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

        e.typeCheckingRuleSet()->addHalfUnificationRule( TCRINFOS, tDeclPat,
            []( const Term& lhs, TypeCheckingContext& c )
            {
                auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
                assert( tdecl );
                return HalfUnify( tdecl->type(), c );
            } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, ANYTERM( _ ), TypeCheckTDecl );
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, tDeclPat, TypeCheckTDecl );








|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    void SetupTDeclTypeChecking( Env& e )
    {
        auto tDeclPat = ValueToEIR( Value( GetValueType< TDecl >(), VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

        e.typeCheckingRuleSet()->addHalfUnificationRule( TCRINFOS, tDeclPat,
            []( const Term& lhs, TypeCheckingContext& c )
            {
                auto tdecl = FromValue< TDecl >( *EIRToValue( lhs ) );
                assert( tdecl );
                return HalfUnify( tdecl->type(), c );
            } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, ANYTERM( _ ), TypeCheckTDecl );
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, tDeclPat, TypeCheckTDecl );

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
            ValueToEIR( ValuePattern(
                TSID( constant ),
                TFuncTypePattern(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
            assert( tdecl );

            auto tfuncType = FromValue< TFuncType >( *ValueFromEIR( tdecl->type() ) );
            assert( tfuncType );

            auto callPat = BuildArgPatternFromTDecl( *tdecl );
            auto tdeclHole = HOLE( tdecl->name() );

            auto rhsVal = *ValueFromEIR( rhs );

            auto constraintPat = BuildTFuncSignature( tcc.context(), *tfuncType );
            assert( constraintPat );

            ConstrainedFunc cfunc( *constraintPat, GetTFuncInvocationRule(), rhsVal );
            auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );








|


|





|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
            ValueToEIR( ValuePattern(
                TSID( constant ),
                TFuncTypePattern(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto tdecl = FromValue< TDecl >( *EIRToValue( lhs ) );
            assert( tdecl );

            auto tfuncType = FromValue< TFuncType >( *EIRToValue( tdecl->type() ) );
            assert( tfuncType );

            auto callPat = BuildArgPatternFromTDecl( *tdecl );
            auto tdeclHole = HOLE( tdecl->name() );

            auto rhsVal = *EIRToValue( rhs );

            auto constraintPat = BuildTFuncSignature( tcc.context(), *tfuncType );
            assert( constraintPat );

            ConstrainedFunc cfunc( *constraintPat, GetTFuncInvocationRule(), rhsVal );
            auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< sema::OverloadSet > >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
            assert( tdecl );

            auto tfuncType = FromValue< TFuncType >( *ValueFromEIR( tdecl->type() ) );
            assert( tfuncType );

            auto callPat = BuildArgPatternFromTDecl( *tdecl );
            auto tdeclHole = HOLE( tdecl->name() );

            auto rhsVal = *ValueFromEIR( rhs );

            auto constraintPat = BuildTFuncSignature( tcc.context(), *tfuncType );
            assert( constraintPat );

            ConstrainedFunc cfunc( *constraintPat, GetOverloadSetInvocationRule(), rhsVal );
            auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );








|


|





|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< sema::OverloadSet > >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto tdecl = FromValue< TDecl >( *EIRToValue( lhs ) );
            assert( tdecl );

            auto tfuncType = FromValue< TFuncType >( *EIRToValue( tdecl->type() ) );
            assert( tfuncType );

            auto callPat = BuildArgPatternFromTDecl( *tdecl );
            auto tdeclHole = HOLE( tdecl->name() );

            auto rhsVal = *EIRToValue( rhs );

            auto constraintPat = BuildTFuncSignature( tcc.context(), *tfuncType );
            assert( constraintPat );

            ConstrainedFunc cfunc( *constraintPat, GetOverloadSetInvocationRule(), rhsVal );
            auto cFuncTerm = ValueToEIR( ToValue( move( cfunc ) ) );

Changes to bs/builtins/types/template/tfunc.cpp.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    {
        return Value( Type( tf ), VEC( Quote( tf.signature() ), tf.identity(),
            TERM( tf.toks() ) ) );
    }

    optional< TFunc > Bridge< TFunc >::FromValue( const Value& v )
    {
        auto typeVal = ValueFromEIR( v.type() );
        auto type = ::FromValue< TFuncType >( *typeVal );
        if( !type )
            return nullopt;

        auto result = Decompose( v.val(),
            Vec(
                SubTerm(),              // signature







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    {
        return Value( Type( tf ), VEC( Quote( tf.signature() ), tf.identity(),
            TERM( tf.toks() ) ) );
    }

    optional< TFunc > Bridge< TFunc >::FromValue( const Value& v )
    {
        auto typeVal = EIRToValue( v.type() );
        auto type = ::FromValue< TFuncType >( *typeVal );
        if( !type )
            return nullopt;

        auto result = Decompose( v.val(),
            Vec(
                SubTerm(),              // signature
Changes to bs/builtins/types/template/tfunctype.cpp.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        );

        return !!result;
    }

    bool IsTFunc( const Value& t )
    {
        return IsTFuncType( *ValueFromEIR( t.type() ) );
    }

    const Term& TFuncPattern::GetPattern()
    {
        static auto pattern = ValueToEIR(
            Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ), HOLE( "_"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ),







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        );

        return !!result;
    }

    bool IsTFunc( const Value& t )
    {
        return IsTFuncType( *EIRToValue( t.type() ) );
    }

    const Term& TFuncPattern::GetPattern()
    {
        static auto pattern = ValueToEIR(
            Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ), HOLE( "_"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ),
Changes to bs/builtins/types/template/tvar.cpp.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
            if( ppVec && !( *ppVec )->empty()
                &&( **ppVec )[0] == TSID( texpr ) )
            {
                return true;
            }
        }

        auto typeVal = ValueFromEIR( te.type() );
        if( !typeVal )
            return false;

        const auto* ppVec = get_if< pvec >( &typeVal->val() );
        if( !ppVec )
            return false;








|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
            if( ppVec && !( *ppVec )->empty()
                &&( **ppVec )[0] == TSID( texpr ) )
            {
                return true;
            }
        }

        auto typeVal = EIRToValue( te.type() );
        if( !typeVal )
            return false;

        const auto* ppVec = get_if< pvec >( &typeVal->val() );
        if( !ppVec )
            return false;

Changes to bs/builtins/types/template/tvec.h.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    // so that they are automatically turned into a suitable TExpr if
    // TExprs are passed as parameters.
    template< typename... T >
    extern Term BuildVecOrTVec( T&&... terms )
    {
        auto vec = Vector::Make( terms... );

        if( ( IsTExpr( ValueFromEIR( terms ) ) || ... ) )
            return TVecToEIR( TVec( move( vec ) ) );

        return vec;
    }

    #define TVEC( ... ) BuildVecOrTVec( __VA_ARGS__ )
}







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    // so that they are automatically turned into a suitable TExpr if
    // TExprs are passed as parameters.
    template< typename... T >
    extern Term BuildVecOrTVec( T&&... terms )
    {
        auto vec = Vector::Make( terms... );

        if( ( IsTExpr( EIRToValue( terms ) ) || ... ) )
            return TVecToEIR( TVec( move( vec ) ) );

        return vec;
    }

    #define TVEC( ... ) BuildVecOrTVec( __VA_ARGS__ )
}
Changes to bs/builtins/types/template/typecheck.cpp.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildCallPatternFromFuncType( *ValueFromEIR( type ) );

            auto rhsVal = *ValueFromEIR( rhs );
            auto tf = *FromValue< TFunc >( rhsVal );

            // Create a new named hole namespace to isolate holes from the passed function from those in
            // the called function.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
            auto localNSId = tcc.newNamespaceIndex();
            tcc.setRHSNamespaceIndex( localNSId );







|

|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildCallPatternFromFuncType( *EIRToValue( type ) );

            auto rhsVal = *EIRToValue( rhs );
            auto tf = *FromValue< TFunc >( rhsVal );

            // Create a new named hole namespace to isolate holes from the passed function from those in
            // the called function.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
            auto localNSId = tcc.newNamespaceIndex();
            tcc.setRHSNamespaceIndex( localNSId );
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                    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 tf = *FromValue< TFunc >( rhsVal );

            // Create a new named hole namespace to isolate holes from the passed function from those in
            // the called function.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
            auto localNSId = tcc.newNamespaceIndex();
            tcc.setRHSNamespaceIndex( localNSId );







|


|







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

            auto&& [sort, type, val, locId] = *ldecomp;
            auto callPat = BuildArgPatternFromTFuncType( tcc.context(), *EIRToValue( type ) );
            assert( callPat );

            auto rhsVal = *EIRToValue( rhs );
            auto tf = *FromValue< TFunc >( rhsVal );

            // Create a new named hole namespace to isolate holes from the passed function from those in
            // the called function.
            auto savedRHSNamespaceIndex = tcc.RHSNamespaceIndex();
            auto localNSId = tcc.newNamespaceIndex();
            tcc.setRHSNamespaceIndex( localNSId );
Changes to bs/builtins/types/tuple/init.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void InitTuple( const Context& c, const Value& tupRef, const Value& initTup )
    {
        G_VAL_ASSERT( tupRef, !tupRef.isConstant() );

        auto lrefType = *FromValue< ReferenceType >( *ValueFromEIR( tupRef.type() ) );

        uint32_t index = 0;
        auto tupType = *ValueFromEIR( lrefType.type() );

        if( TupleTypeSize( tupType ) != TupleSize( initTup ) )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( 0, "Incompatible tuple sizes." );
            return;
        }

        ForEachInTupleType( tupType, [&]( auto&& t )
        {
            auto elemType = *ValueFromEIR( t );

            // Create a mutable reference to the element to initialize
            ReferenceType rt( t, TSID( mut ) );
            auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
                Select( tupRef.cir(), index ) ).setLocationId( elemType.locationId() );

            auto elemInit = *ValueFromEIR( GetTupleElement( initTup, index++ ) );

            DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
            auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
                MakeTuple( elemRef, move( elemInit ) ) );

            DiagnosticsContext dc2( elemType.locationId(), "When invoking DropValue." );
                InvokeOverloadSet( c, c.env()->extDropValue(),












|


|









|






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "builtins/builtins.h"
#include "parse/parse.h"

using namespace goose::parse;
using namespace goose::cir;

namespace goose::builtins
{
    void InitTuple( const Context& c, const Value& tupRef, const Value& initTup )
    {
        G_VAL_ASSERT( tupRef, !tupRef.isConstant() );

        auto lrefType = *FromValue< ReferenceType >( *EIRToValue( tupRef.type() ) );

        uint32_t index = 0;
        auto tupType = *EIRToValue( lrefType.type() );

        if( TupleTypeSize( tupType ) != TupleSize( initTup ) )
        {
            DiagnosticsManager::GetInstance().emitErrorMessage( 0, "Incompatible tuple sizes." );
            return;
        }

        ForEachInTupleType( tupType, [&]( auto&& t )
        {
            auto elemType = *EIRToValue( t );

            // Create a mutable reference to the element to initialize
            ReferenceType rt( t, TSID( mut ) );
            auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
                Select( tupRef.cir(), index ) ).setLocationId( elemType.locationId() );

            auto elemInit = *EIRToValue( GetTupleElement( initTup, index++ ) );

            DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
            auto init = InvokeOverloadSet( c, c.env()->extInitialize(),
                MakeTuple( elemRef, move( elemInit ) ) );

            DiagnosticsContext dc2( elemType.locationId(), "When invoking DropValue." );
                InvokeOverloadSet( c, c.env()->extDropValue(),
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        // Tuples default initialization: attempt to default initialize every element.
        RegisterBuiltinFunc< Intrinsic< void (
                CustomPattern< Value, ReferenceType::PatternMutable< TuplePattern > >
                ) > >( e, e.extInitialize(),
            []( const Context& c, const Value& tupRef )
            {
                G_VAL_ASSERT( tupRef, !tupRef.isConstant() );
                auto refType = *FromValue< ReferenceType >( *ValueFromEIR( tupRef.type() ) );

                uint32_t index = 0;
                auto tupType = *ValueFromEIR( refType.type() );

                ForEachInTupleType( tupType, [&]( auto&& t )
                {
                    auto elemType = *ValueFromEIR( t );

                    // Create a mutable reference to the element to initialize
                    ReferenceType rt( t, TSID( mut ) );
                    auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
                        Select( tupRef.cir(), index++ ) ).setLocationId( elemType.locationId() );

                    DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );







|


|



|







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        // Tuples default initialization: attempt to default initialize every element.
        RegisterBuiltinFunc< Intrinsic< void (
                CustomPattern< Value, ReferenceType::PatternMutable< TuplePattern > >
                ) > >( e, e.extInitialize(),
            []( const Context& c, const Value& tupRef )
            {
                G_VAL_ASSERT( tupRef, !tupRef.isConstant() );
                auto refType = *FromValue< ReferenceType >( *EIRToValue( tupRef.type() ) );

                uint32_t index = 0;
                auto tupType = *EIRToValue( refType.type() );

                ForEachInTupleType( tupType, [&]( auto&& t )
                {
                    auto elemType = *EIRToValue( t );

                    // Create a mutable reference to the element to initialize
                    ReferenceType rt( t, TSID( mut ) );
                    auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
                        Select( tupRef.cir(), index++ ) ).setLocationId( elemType.locationId() );

                    DiagnosticsContext dc( elemType.locationId(), "When invoking Initialize." );
Changes to bs/builtins/types/tuple/lower.cpp.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
            []( const Context& c, const Value& tupType )
        {
            RecordType rt;
            bool success = true;

            ForEachInTupleType( tupType, [&]( auto&& t )
            {
                auto loweredType = LowerTypeForRuntime( c, *ValueFromEIR( t ) );
                if( !loweredType || loweredType->isPoison() )
                {
                    success = false;
                    return false;
                }

                rt.m_memberTypes->append( ValueToEIR( *loweredType ) );







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
            []( const Context& c, const Value& tupType )
        {
            RecordType rt;
            bool success = true;

            ForEachInTupleType( tupType, [&]( auto&& t )
            {
                auto loweredType = LowerTypeForRuntime( c, *EIRToValue( t ) );
                if( !loweredType || loweredType->isPoison() )
                {
                    success = false;
                    return false;
                }

                rt.m_memberTypes->append( ValueToEIR( *loweredType ) );
Changes to bs/builtins/types/tuple/tuple.cpp.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    {
        static auto val = Value( ValueToEIR( EmptyClosedTupleType() ), VEC() );
        return val;
    }

    Value AppendToTuple( const Value& tup, const ValuePattern& valPat )
    {
        auto tupType = ValueFromEIR( tup.type() );
        assert( tupType );

        auto result = Value(
            ValueToEIR( AppendToTupleType( *tupType, valPat.type() ) ),
            AppendToVectorTerm( tup.val(), ValueToEIR( valPat ) ) );

        if( tup.isPoison() || valPat.isPoison() )
            result.setPoison();

        return result;
    }

    Value AppendToTuple( const Value& tup, const Value& val )
    {
        auto tupType = ValueFromEIR( tup.type() );
        auto valType = ValueFromEIR( val.type() );

        assert( tupType );
        assert( valType );

        auto result = Value(
            ValueToEIR( AppendToTupleType( *tupType, *valType ) ),
            AppendToVectorTerm( tup.val(), ValueToEIR( val ) ) );

        if( tup.isPoison() || val.isPoison() )
            result.setPoison();

        return result;
    }

    Value PrependToTuple( const Value& val, const Value& tup )
    {
        auto tupType = ValueFromEIR( tup.type() );
        auto valType = ValueFromEIR( val.type() );

        assert( tupType );
        assert( valType );

        auto result = Value(
            ValueToEIR( PrependToTupleType( *valType, *tupType ) ),
            PrependToVectorTerm( tup.val(), ValueToEIR( val ) ) );

        if( tup.isPoison() || val.isPoison() )
            result.setPoison();

        return result;
    }

    Value ConcatenateTuples( const Value& ltup, const Value& rtup )
    {
        auto ltupType = ValueFromEIR( ltup.type() );
        auto rtupType = ValueFromEIR( rtup.type() );

        assert( ltupType );
        assert( rtupType );

        auto result = Value(
            ValueToEIR( ConcatenateTupleTypes( *ltupType, *rtupType ) ),
            ConcatenateVectorTerms( ltup.val(), rtup.val() ) );

        if( ltup.isPoison() || rtup.isPoison() )
            result.setPoison();

        return result;
    }

    bool IsTuple( const Value& t )
    {
        auto typeVal = ValueFromEIR( t.type() );

        if( !typeVal || !typeVal->isConstant() )
            return false;

        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );

        return !!result;
    }

    bool IsOpenTuple( const Value& t )
    {
        if( !t.isConstant() )
            return false;

        auto typeVal = ValueFromEIR( t.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                Lit( "open"_sid ),
                SubTerm()
            )
        );

        return !!result;
    }

    Value CloseTuple( const Value& tup )
    {
        auto tupType = ValueFromEIR( tup.type() );
        return Value( ValueToEIR( ToClosedTupleType( *tupType ) ),
            tup.val() ).setLocationId( tup.locationId() );
    }

    size_t TupleSize( const Value& tup )
    {
        const auto& vec = *get< pvec >( tup.val() );
        return vec.terms().size();
    }

    const Term& GetTupleElementType( const Value& tup, uint32_t index )
    {
        return GetTupleTypeElement( *ValueFromEIR( tup.type() ), index );
    }

    const Term& GetTupleElement( const Value& tup, uint32_t index )
    {
        const auto& vec = *get< pvec >( tup.val() );
        return vec.terms()[index];
    }







|














|
|
















|
|
















|
|
















|




















|













|












|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    {
        static auto val = Value( ValueToEIR( EmptyClosedTupleType() ), VEC() );
        return val;
    }

    Value AppendToTuple( const Value& tup, const ValuePattern& valPat )
    {
        auto tupType = EIRToValue( tup.type() );
        assert( tupType );

        auto result = Value(
            ValueToEIR( AppendToTupleType( *tupType, valPat.type() ) ),
            AppendToVectorTerm( tup.val(), ValueToEIR( valPat ) ) );

        if( tup.isPoison() || valPat.isPoison() )
            result.setPoison();

        return result;
    }

    Value AppendToTuple( const Value& tup, const Value& val )
    {
        auto tupType = EIRToValue( tup.type() );
        auto valType = EIRToValue( val.type() );

        assert( tupType );
        assert( valType );

        auto result = Value(
            ValueToEIR( AppendToTupleType( *tupType, *valType ) ),
            AppendToVectorTerm( tup.val(), ValueToEIR( val ) ) );

        if( tup.isPoison() || val.isPoison() )
            result.setPoison();

        return result;
    }

    Value PrependToTuple( const Value& val, const Value& tup )
    {
        auto tupType = EIRToValue( tup.type() );
        auto valType = EIRToValue( val.type() );

        assert( tupType );
        assert( valType );

        auto result = Value(
            ValueToEIR( PrependToTupleType( *valType, *tupType ) ),
            PrependToVectorTerm( tup.val(), ValueToEIR( val ) ) );

        if( tup.isPoison() || val.isPoison() )
            result.setPoison();

        return result;
    }

    Value ConcatenateTuples( const Value& ltup, const Value& rtup )
    {
        auto ltupType = EIRToValue( ltup.type() );
        auto rtupType = EIRToValue( rtup.type() );

        assert( ltupType );
        assert( rtupType );

        auto result = Value(
            ValueToEIR( ConcatenateTupleTypes( *ltupType, *rtupType ) ),
            ConcatenateVectorTerms( ltup.val(), rtup.val() ) );

        if( ltup.isPoison() || rtup.isPoison() )
            result.setPoison();

        return result;
    }

    bool IsTuple( const Value& t )
    {
        auto typeVal = EIRToValue( t.type() );

        if( !typeVal || !typeVal->isConstant() )
            return false;

        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );

        return !!result;
    }

    bool IsOpenTuple( const Value& t )
    {
        if( !t.isConstant() )
            return false;

        auto typeVal = EIRToValue( t.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                Lit( "open"_sid ),
                SubTerm()
            )
        );

        return !!result;
    }

    Value CloseTuple( const Value& tup )
    {
        auto tupType = EIRToValue( tup.type() );
        return Value( ValueToEIR( ToClosedTupleType( *tupType ) ),
            tup.val() ).setLocationId( tup.locationId() );
    }

    size_t TupleSize( const Value& tup )
    {
        const auto& vec = *get< pvec >( tup.val() );
        return vec.terms().size();
    }

    const Term& GetTupleElementType( const Value& tup, uint32_t index )
    {
        return GetTupleTypeElement( *EIRToValue( tup.type() ), index );
    }

    const Term& GetTupleElement( const Value& tup, uint32_t index )
    {
        const auto& vec = *get< pvec >( tup.val() );
        return vec.terms()[index];
    }
Changes to bs/builtins/types/tuple/tuple.inl.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    {
        // Check that the tuple's payload is a vector. It might be a hole.
        if( !holds_alternative< pvec >( tup.val() ) )
            return;

        ForEachInVectorTerm( tup.val(), [&]( auto&& t )
        {
            return func( *ValueFromEIR( t ) );
        } );
    }

    template< typename F >
    void ForEachInTupleType( const Value& tupType, F&& func )
    {
        auto decomp = Decompose( tupType.val(),







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    {
        // Check that the tuple's payload is a vector. It might be a hole.
        if( !holds_alternative< pvec >( tup.val() ) )
            return;

        ForEachInVectorTerm( tup.val(), [&]( auto&& t )
        {
            return func( *EIRToValue( t ) );
        } );
    }

    template< typename F >
    void ForEachInTupleType( const Value& tupType, F&& func )
    {
        auto decomp = Decompose( tupType.val(),
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

    template< typename H, typename... T >
    static Value BuildTupleType( const Value& typeSoFar )
    {
        if constexpr( sizeof...( T ) > 1 )
        {
            return BuildTupleType< T... >( builtins::AppendToTupleType( typeSoFar,
                *ValueFromEIR( GetValueType< H >() ) ) );
        }
        else
            return builtins::AppendToTupleType( typeSoFar, *ValueFromEIR( GetValueType< H >() ) );
    }

    template< typename... T >
    const Term& Bridge< tuple< T... > >::Type()
    {
        if constexpr( sizeof... ( T ) == 0 )
        {







|


|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

    template< typename H, typename... T >
    static Value BuildTupleType( const Value& typeSoFar )
    {
        if constexpr( sizeof...( T ) > 1 )
        {
            return BuildTupleType< T... >( builtins::AppendToTupleType( typeSoFar,
                *EIRToValue( GetValueType< H >() ) ) );
        }
        else
            return builtins::AppendToTupleType( typeSoFar, *EIRToValue( GetValueType< H >() ) );
    }

    template< typename... T >
    const Term& Bridge< tuple< T... > >::Type()
    {
        if constexpr( sizeof... ( T ) == 0 )
        {
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    template< typename TT, size_t... I >
    optional< TT > BuildTupleFromValueVec( const Vector& vec, index_sequence< I... > )
    {
        if constexpr( sizeof... ( I ) == 0 )
            return TT();
        else
        {
            auto values = make_tuple( ValueFromEIR( vec[I] )... );
            if( ( !get< I >( values ) || ... ) )
                return nullopt;

            auto items = make_tuple( FromValue< tuple_element_t< I, TT > >( *get< I >( values ) )... );
            if( ( !get< I >( items ) || ... ) )
                return nullopt;








|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    template< typename TT, size_t... I >
    optional< TT > BuildTupleFromValueVec( const Vector& vec, index_sequence< I... > )
    {
        if constexpr( sizeof... ( I ) == 0 )
            return TT();
        else
        {
            auto values = make_tuple( EIRToValue( vec[I] )... );
            if( ( !get< I >( values ) || ... ) )
                return nullopt;

            auto items = make_tuple( FromValue< tuple_element_t< I, TT > >( *get< I >( values ) )... );
            if( ( !get< I >( items ) || ... ) )
                return nullopt;

Changes to bs/builtins/types/tuple/tupletype.cpp.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    Value MkTupleType( const Term& state, const Term& types )
    {
        return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
    }

    extern Value TupleOfTypesToTupleType( const Value& tup )
    {
        auto typeVal = ValueFromEIR( tup.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    Value MkTupleType( const Term& state, const Term& types )
    {
        return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
    }

    extern Value TupleOfTypesToTupleType( const Value& tup )
    {
        auto typeVal = EIRToValue( tup.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );
Changes to bs/builtins/types/tuple/typecheck.cpp.
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
                TSID( constant ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                VECOFLENGTH( L ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromEIR( lhs );
            auto rtup = ValueFromEIR( rhs );

            if( !ltup || !rtup )
                co_return;

            auto tupType = *ValueFromEIR( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleSize( *rtup ) );

            co_yield TypeCheckConstantTuple( tcc, tupType, *rtup, 0, EmptyTuple() );
        } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                TSID( computed ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromEIR( lhs );
            auto rtup = ValueFromEIR( rhs );

            if( !ltup || !rtup || !tcc.context().codeBuilder() )
                co_return;

            auto tupType = *ValueFromEIR( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromEIR( rtup->type() ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();

            auto rtupref = BuildComputedValue( ValueToEIR( ToValue( ReferenceType{ rtup->type(), TSID( const ) } ) ),
                cir::TempAddr( tempIndex, *rtup ) );

            co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, rtupref, 0, EmptyTuple() );







|




|




















|




|
|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
                TSID( constant ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                VECOFLENGTH( L ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromEIR( lhs );
            auto rtup = EIRToValue( rhs );

            if( !ltup || !rtup )
                co_return;

            auto tupType = *EIRToValue( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleSize( *rtup ) );

            co_yield TypeCheckConstantTuple( tcc, tupType, *rtup, 0, EmptyTuple() );
        } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                TSID( computed ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromEIR( lhs );
            auto rtup = EIRToValue( rhs );

            if( !ltup || !rtup || !tcc.context().codeBuilder() )
                co_return;

            auto tupType = *EIRToValue( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleTypeSize( *EIRToValue( rtup->type() ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();

            auto rtupref = BuildComputedValue( ValueToEIR( ToValue( ReferenceType{ rtup->type(), TSID( const ) } ) ),
                cir::TempAddr( tempIndex, *rtup ) );

            co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, rtupref, 0, EmptyTuple() );
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
            ValueToEIR( ValuePattern(
                TSID( constant ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto tup = ValueFromEIR( rhs );
            if( !tup )
                co_return;

            const auto& vec1 = *get< pvec >( tup->val() );
            co_yield TypeCheck( lhs, vec1[0], tcc );
        } );








|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
            ValueToEIR( ValuePattern(
                TSID( constant ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto tup = EIRToValue( rhs );
            if( !tup )
                co_return;

            const auto& vec1 = *get< pvec >( tup->val() );
            co_yield TypeCheck( lhs, vec1[0], tcc );
        } );

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
            ValueToEIR( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto tup = ValueFromEIR( lhs );
            if( !tup )
                co_return;

            const auto& vec1 = *get< pvec >( tup->val() );

            // In some cases, the tuple may not be an actual tuple value but merely
            // a pattern for a tuple value, with a hole instead of its content vector.







|







148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
            ValueToEIR( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto tup = EIRToValue( lhs );
            if( !tup )
                co_return;

            const auto& vec1 = *get< pvec >( tup->val() );

            // In some cases, the tuple may not be an actual tuple value but merely
            // a pattern for a tuple value, with a hole instead of its content vector.
Changes to bs/cir/call.cpp.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

        if( IsExternalFunc( m_func ) )
            return false;

        bool argsCanBeExecuted = true;
        ForEachInVectorTerm( m_args, [&]( auto&& arg )
        {
            if( !IsValueConstantOrExecutable( *ValueFromEIR( arg ) ) )
            {
                argsCanBeExecuted = false;
                return false;
            }

            return true;
        } );







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

        if( IsExternalFunc( m_func ) )
            return false;

        bool argsCanBeExecuted = true;
        ForEachInVectorTerm( m_args, [&]( auto&& arg )
        {
            if( !IsValueConstantOrExecutable( *EIRToValue( arg ) ) )
            {
                argsCanBeExecuted = false;
                return false;
            }

            return true;
        } );
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

        if( IsExternalFunc( m_func ) )
            return false;

        bool argsAreConstant = true;
        ForEachInVectorTerm( m_args, [&]( auto&& arg )
        {
            if( !CanValueBeEagerlyEvaluated( *ValueFromEIR( arg ) ) )
            {
                argsAreConstant = false;
                return false;
            }

            return true;
        } );







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

        if( IsExternalFunc( m_func ) )
            return false;

        bool argsAreConstant = true;
        ForEachInVectorTerm( m_args, [&]( auto&& arg )
        {
            if( !CanValueBeEagerlyEvaluated( *EIRToValue( arg ) ) )
            {
                argsAreConstant = false;
                return false;
            }

            return true;
        } );
Changes to bs/codegen/instructions.cpp.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

    const auto& vec = *get< pvec >( call.args() );
    vector< llvm::Value* > args;
    args.reserve( vec.terms().size() );

    for( auto&& a : vec.terms() )
    {
        auto* parg = buildValue( inf, *ValueFromEIR( a ) );
        if( !parg )
            return nullptr;

        args.emplace_back( parg );
    }

    return m_llvmBuilder.CreateCall( llvm::FunctionCallee( llvmCallee ), args );







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

    const auto& vec = *get< pvec >( call.args() );
    vector< llvm::Value* > args;
    args.reserve( vec.terms().size() );

    for( auto&& a : vec.terms() )
    {
        auto* parg = buildValue( inf, *EIRToValue( a ) );
        if( !parg )
            return nullptr;

        args.emplace_back( parg );
    }

    return m_llvmBuilder.CreateCall( llvm::FunctionCallee( llvmCallee ), args );
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
    createTemporary( inf, av.index(), pAlloca );
    return pAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Load& load )
{
    auto type = LowerTypeForRuntime( inf.context, *ValueFromEIR( load.type() ) );
    if( !type )
        return nullptr;

    auto* llvmType = GetLLVMType( *type );
    assert( llvmType );

    auto* ptrVal = buildInstruction( inf, *load.addr() );







|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    auto* pAlloca = buildAlloca( inf, GetLLVMType( *type ) );
    createTemporary( inf, av.index(), pAlloca );
    return pAlloca;
}

llvm::Value* Module::buildInstruction( Infos& inf, const cir::Load& load )
{
    auto type = LowerTypeForRuntime( inf.context, *EIRToValue( load.type() ) );
    if( !type )
        return nullptr;

    auto* llvmType = GetLLVMType( *type );
    assert( llvmType );

    auto* ptrVal = buildInstruction( inf, *load.addr() );
Changes to bs/codegen/value.cpp.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    {
        return *b ?
            llvm::ConstantInt::getTrue( GetLLVMContext() ) :
            llvm::ConstantInt::getFalse( GetLLVMContext() );
    }
    else if( auto intVal = FromValue< APSInt >( *val ) )
    {
        return llvm::ConstantInt::get( GetLLVMType( *ValueFromEIR( val->type() ) ),
            *FromValue< APSInt >( *val ) );
    }
    else if( auto ptType = FromValue< PointerType >( *ValueFromEIR( val->type() ) ) )
    {
        return buildConstantPointer( inf, *ptType, *val );
    }
    else if( auto recType = FromValue< RecordType >( *ValueFromEIR( val->type() ) ) )
    {
        llvm::SmallVector< llvm::Constant*, 8 > members;
        assert( holds_alternative< pvec >( val->val() ) );

        bool success = true;

        ForEachInVectorTerm( val->val(), [&]( auto&& t )
        {
            auto* pMemberVal = buildConstant( inf, *ValueFromEIR( t ) );
            if( !pMemberVal )
            {
                success = false;
                return false;
            }

            members.push_back( pMemberVal );
            return true;
        } );

        if( !success )
            return nullptr;

        return llvm::ConstantStruct::get( static_cast< llvm::StructType* >
            ( GetLLVMType( *ValueFromEIR( val->type() ) ) ), members );
    }

    DiagnosticsManager::GetInstance().emitErrorMessage(
        v.locationId(), "constants with compile time types are not supported.", 0 );
    return nullptr;
}








|


|



|








|














|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    {
        return *b ?
            llvm::ConstantInt::getTrue( GetLLVMContext() ) :
            llvm::ConstantInt::getFalse( GetLLVMContext() );
    }
    else if( auto intVal = FromValue< APSInt >( *val ) )
    {
        return llvm::ConstantInt::get( GetLLVMType( *EIRToValue( val->type() ) ),
            *FromValue< APSInt >( *val ) );
    }
    else if( auto ptType = FromValue< PointerType >( *EIRToValue( val->type() ) ) )
    {
        return buildConstantPointer( inf, *ptType, *val );
    }
    else if( auto recType = FromValue< RecordType >( *EIRToValue( val->type() ) ) )
    {
        llvm::SmallVector< llvm::Constant*, 8 > members;
        assert( holds_alternative< pvec >( val->val() ) );

        bool success = true;

        ForEachInVectorTerm( val->val(), [&]( auto&& t )
        {
            auto* pMemberVal = buildConstant( inf, *EIRToValue( t ) );
            if( !pMemberVal )
            {
                success = false;
                return false;
            }

            members.push_back( pMemberVal );
            return true;
        } );

        if( !success )
            return nullptr;

        return llvm::ConstantStruct::get( static_cast< llvm::StructType* >
            ( GetLLVMType( *EIRToValue( val->type() ) ) ), members );
    }

    DiagnosticsManager::GetInstance().emitErrorMessage(
        v.locationId(), "constants with compile time types are not supported.", 0 );
    return nullptr;
}

98
99
100
101
102
103
104
105
106
        else
            pGlob = it->second;

        return pGlob;
    }

    return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
        ( GetLLVMType( *ValueFromEIR( v.type() ) ) ) );
}







|

98
99
100
101
102
103
104
105
106
        else
            pGlob = it->second;

        return pGlob;
    }

    return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
        ( GetLLVMType( *EIRToValue( v.type() ) ) ) );
}
Changes to bs/compile/compiler.cpp.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
        llvm::InitializeAllTargetMCs();
        llvm::InitializeAllAsmPrinters();
        llvm::InitializeAllAsmParsers();
    }

    uint32_t Compiler::execute( const string& filename )
    {
        auto locVarsIdentity = AppendToVectorTerm( builtins::RootIdentity(), TSID( locvars ) );
        m_pEnv->addVisibilityRule( builtins::RootIdentity(), locVarsIdentity );
        auto result = LoadAndExecuteFile( m_pEnv, filename, locVarsIdentity, GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );

        if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
            return 1;

        if( !result )
        {







|
|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
        llvm::InitializeAllTargetMCs();
        llvm::InitializeAllAsmPrinters();
        llvm::InitializeAllAsmParsers();
    }

    uint32_t Compiler::execute( const string& filename )
    {
        auto locVarsIdentity = AppendToVectorTerm( builtins::RootG0Identity(), TSID( locvars ) );
        m_pEnv->addVisibilityRule( builtins::RootG0Identity(), locVarsIdentity );
        auto result = LoadAndExecuteFile( m_pEnv, filename, locVarsIdentity, GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );

        if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
            return 1;

        if( !result )
        {
Changes to bs/eir/term.h.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72



73
74
75
76
77
78
79
        LocationId,
        string,
        StringId,
        Delimiter,
        Hole,
        AnyTerm,
        VecOfLength,
        ptr< void >,
        void*,
        pvec,

        // Representation for ct_int, the compile time only integers
        // with "unlimited" precision
        BigInt,

        // Compile time representation for normal, fixed size integers
        APSInt



    >;

    extern bool operator==( const Term& lhs, const Term& rhs );
    extern bool operator!=( const Term& lhs, const Term& rhs );

    struct STerm
    {







<
<







|
>
>
>







56
57
58
59
60
61
62


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
        LocationId,
        string,
        StringId,
        Delimiter,
        Hole,
        AnyTerm,
        VecOfLength,


        pvec,

        // Representation for ct_int, the compile time only integers
        // with "unlimited" precision
        BigInt,

        // Compile time representation for normal, fixed size integers
        APSInt,

        ptr< void >,
        void*
    >;

    extern bool operator==( const Term& lhs, const Term& rhs );
    extern bool operator!=( const Term& lhs, const Term& rhs );

    struct STerm
    {
Changes to bs/eir/value.cpp.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        }

        return VEC( TSID( value ), TSID( computed ), v.type(),
            TERM( static_pointer_cast< void >( v.cir() ) ),
            static_cast< LocationId >( v.locationId() ) );
    }

    optional< Value > ValueFromEIR( const Term& t )
    {
        // Special case for type's type
        auto typedecomp = Decompose( t,
            Vec(
                Lit( "type"_sid ),
                Val< uint32_t >(),
                Val< LocationId >()







|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        }

        return VEC( TSID( value ), TSID( computed ), v.type(),
            TERM( static_pointer_cast< void >( v.cir() ) ),
            static_cast< LocationId >( v.locationId() ) );
    }

    optional< Value > EIRToValue( const Term& t )
    {
        // Special case for type's type
        auto typedecomp = Decompose( t,
            Vec(
                Lit( "type"_sid ),
                Val< uint32_t >(),
                Val< LocationId >()
Changes to bs/eir/value.h.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    class Value;
    class ValuePattern;

    extern const Term& TypeType();

    extern Term ValueToEIR( const Value& v );
    extern optional< Value > ValueFromEIR( const Term& t );

    extern Term ValueToEIR( const ValuePattern& v );
    extern optional< ValuePattern > ValuePatternFromEIR( const Term& t );

    class Value
    {
        public:







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
    class Value;
    class ValuePattern;

    extern const Term& TypeType();

    extern Term ValueToEIR( const Value& v );
    extern optional< Value > EIRToValue( const Term& t );

    extern Term ValueToEIR( const ValuePattern& v );
    extern optional< ValuePattern > ValuePatternFromEIR( const Term& t );

    class Value
    {
        public:
Changes to bs/execute/vm.cpp.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    bool poisoned = false;
    const auto& vec = *get< pvec >( call.args() );

    if( IsBuiltinFunc( func ) )
    {
        auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
        {
            auto val = ValueFromEIR( x );
            assert( val );

            auto newVal = Evaluate( *val, *this );
            if( newVal.isPoison() )
                poisoned = true;

            if( !newVal.isConstant() )







|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    bool poisoned = false;
    const auto& vec = *get< pvec >( call.args() );

    if( IsBuiltinFunc( func ) )
    {
        auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
        {
            auto val = EIRToValue( x );
            assert( val );

            auto newVal = Evaluate( *val, *this );
            if( newVal.isPoison() )
                poisoned = true;

            if( !newVal.isConstant() )
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    if( !pFunc || !pFunc->isValid() )
        return PoisonValue();

    auto savedStackSize = m_stack.size();

    for( auto&& a : vec.terms() )
    {
        auto val = ValueFromEIR( a );
        assert( val );

        auto newVal = Evaluate( *val, *this );
        if( newVal.isPoison()  )
        {
            m_stack.resize( savedStackSize );
            return PoisonValue();







|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    if( !pFunc || !pFunc->isValid() )
        return PoisonValue();

    auto savedStackSize = m_stack.size();

    for( auto&& a : vec.terms() )
    {
        auto val = EIRToValue( a );
        assert( val );

        auto newVal = Evaluate( *val, *this );
        if( newVal.isPoison()  )
        {
            m_stack.resize( savedStackSize );
            return PoisonValue();
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    if( !baseAddr || baseAddr->isPoison() )
        return nullopt;

    auto pvoid = FromValue< Term* >( *baseAddr );
    if( !pvoid )
        return nullopt;

    auto val = ValueFromEIR( *static_cast< Term* >( pvoid ) );
    if( !val )
        return nullopt;

    // We only support tuples now. In the future, Select will also be used to
    // add an offset to another pointer.
    // Everything else (structs, classes, containers, etc.) should build on top
    // of those two fundamental types.







|







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
    if( !baseAddr || baseAddr->isPoison() )
        return nullopt;

    auto pvoid = FromValue< Term* >( *baseAddr );
    if( !pvoid )
        return nullopt;

    auto val = EIRToValue( *static_cast< Term* >( pvoid ) );
    if( !val )
        return nullopt;

    // We only support tuples now. In the future, Select will also be used to
    // add an offset to another pointer.
    // Everything else (structs, classes, containers, etc.) should build on top
    // of those two fundamental types.
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

optional< Value > VM::execute( const cir::GetTemporary& gt )
{
    auto stackIndex = gt.index() + m_currentFrameStart;
    if( stackIndex >= m_stack.size() )
        return nullopt;

    return ValueFromEIR( *m_stack[stackIndex] );
}

optional< Value > VM::execute( const cir::AllocVar& av )
{
    auto stackIndex = m_currentFrameStart + av.index();

    if( m_stack.size() <= stackIndex )







|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

optional< Value > VM::execute( const cir::GetTemporary& gt )
{
    auto stackIndex = gt.index() + m_currentFrameStart;
    if( stackIndex >= m_stack.size() )
        return nullopt;

    return EIRToValue( *m_stack[stackIndex] );
}

optional< Value > VM::execute( const cir::AllocVar& av )
{
    auto stackIndex = m_currentFrameStart + av.index();

    if( m_stack.size() <= stackIndex )
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
    if( !baseAddr || baseAddr->isPoison() )
        return nullopt;

    auto addr = FromValue< Term* >( *baseAddr );
    if( !addr )
        return nullopt;

    return ValueFromEIR( *addr );
}

optional< Value > VM::execute( const cir::Store& s )
{
    auto baseAddr = execute( *s.addr() );
    if( !baseAddr || baseAddr->isPoison() )
        return nullopt;







|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
    if( !baseAddr || baseAddr->isPoison() )
        return nullopt;

    auto addr = FromValue< Term* >( *baseAddr );
    if( !addr )
        return nullopt;

    return EIRToValue( *addr );
}

optional< Value > VM::execute( const cir::Store& s )
{
    auto baseAddr = execute( *s.addr() );
    if( !baseAddr || baseAddr->isPoison() )
        return nullopt;
367
368
369
370
371
372
373
374
375
376
377
378
379
        return make_shared< Term >( TSID( UNINITIALIZED ) );

    auto tupContent = make_shared< Vector >();
    tupContent->reserve( TupleTypeSize( type ) );

    ForEachInTupleType( type, [&]( auto&& t )
    {
        tupContent->append( *BuildUninitializedValue( *ValueFromEIR( t ) ) );
        return true;
    } );

    return make_shared< Term >( ValueToEIR( Value( ValueToEIR( type ), TERM( move( tupContent ) ) ) ) );
}







|





367
368
369
370
371
372
373
374
375
376
377
378
379
        return make_shared< Term >( TSID( UNINITIALIZED ) );

    auto tupContent = make_shared< Vector >();
    tupContent->reserve( TupleTypeSize( type ) );

    ForEachInTupleType( type, [&]( auto&& t )
    {
        tupContent->append( *BuildUninitializedValue( *EIRToValue( t ) ) );
        return true;
    } );

    return make_shared< Term >( ValueToEIR( Value( ValueToEIR( type ), TERM( move( tupContent ) ) ) ) );
}
Changes to bs/g0api/cgapi/func.cpp.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    void SetupApiCGFunc( Env& e )
    {
        weak_ptr< Env > pEnv = e.shared_from_this();

        RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern > ) >( e, "CGGenerateFunction"_sid,
            [pEnv]( const ptr< codegen::Module >& module, const Value& f )
            {
                if( !IsFuncType( *ValueFromEIR( f.type() ) ) )
                    return false;

                sema::Context c( pEnv.lock(), RootIdentity() );

                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                auto func = CompileFunc( c, f );
                if( func.isPoison() || DiagnosticsManager::GetInstance().errorsWereEmitted() )
                    return false;

                auto llvmFunc = module->getOrCreateFunc( c, *FromValue< Func >( func ) );
                return !!llvmFunc;
            } );

        RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern >, string ) >( e, "CGGenerateFunction"_sid,
            [pEnv]( const ptr< codegen::Module >& module, const Value& f, const string& name )
            {
                if( !IsFuncType( *ValueFromEIR( f.type() ) ) )
                    return false;

                sema::Context c( pEnv.lock(), RootIdentity() );

                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                auto func = CompileFunc( c, f );
                if( func.isPoison() || DiagnosticsManager::GetInstance().errorsWereEmitted() )
                    return false;

                auto llvmFunc = module->getOrCreateFunc( c, *FromValue< Func >( func ), name, llvm::Function::ExternalLinkage );
                return !!llvmFunc;
            } );
    }
}







|


|















|


|













8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    void SetupApiCGFunc( Env& e )
    {
        weak_ptr< Env > pEnv = e.shared_from_this();

        RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern > ) >( e, "CGGenerateFunction"_sid,
            [pEnv]( const ptr< codegen::Module >& module, const Value& f )
            {
                if( !IsFuncType( *EIRToValue( f.type() ) ) )
                    return false;

                sema::Context c( pEnv.lock(), RootG0Identity() );

                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                auto func = CompileFunc( c, f );
                if( func.isPoison() || DiagnosticsManager::GetInstance().errorsWereEmitted() )
                    return false;

                auto llvmFunc = module->getOrCreateFunc( c, *FromValue< Func >( func ) );
                return !!llvmFunc;
            } );

        RegisterBuiltinFunc< bool ( ptr< codegen::Module >, CustomPattern< Value, FuncPattern >, string ) >( e, "CGGenerateFunction"_sid,
            [pEnv]( const ptr< codegen::Module >& module, const Value& f, const string& name )
            {
                if( !IsFuncType( *EIRToValue( f.type() ) ) )
                    return false;

                sema::Context c( pEnv.lock(), RootG0Identity() );

                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                auto func = CompileFunc( c, f );
                if( func.isPoison() || DiagnosticsManager::GetInstance().errorsWereEmitted() )
                    return false;

                auto llvmFunc = module->getOrCreateFunc( c, *FromValue< Func >( func ), name, llvm::Function::ExternalLinkage );
                return !!llvmFunc;
            } );
    }
}
Changes to bs/g0api/compiler.cpp.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
                        "CreateConstant: the expression doesn't evaluate to a constant." );
                    return;
                }

                pEnv.lock()->storeValue(
                    AppendToVectorTerm( RootIdentity(), StringId( name.c_str() ) ),
                    ANYTERM( _ ), ValueToEIR( v ) );
            } );

        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
            [pEnv]( auto&& c, const Value& fnameval ) -> Value
            {
                auto filename = *FromValue< string >( fnameval );







|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( v.locationId(),
                        "CreateConstant: the expression doesn't evaluate to a constant." );
                    return;
                }

                pEnv.lock()->storeValue(
                    AppendToVectorTerm( RootG0Identity(), StringId( name.c_str() ) ),
                    ANYTERM( _ ), ValueToEIR( v ) );
            } );

        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
            [pEnv]( auto&& c, const Value& fnameval ) -> Value
            {
                auto filename = *FromValue< string >( fnameval );
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
            } );

        RegisterBuiltinFunc< uint32_t ( string ) >( e, "ExecuteFile"_sid,
            [pEnv]( const string& filename ) -> Value
            {
                // For now generate an unique identity for the file to execute. Later we might want to
                // pass an identity as parameters as a wrapped term.
                auto identity = AppendToVectorTerm( RootIdentity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );
                auto locVarsIdentity = AppendToVectorTerm( identity, TSID( locvars ) );

                auto env = pEnv.lock();
                env->addVisibilityRule( builtins::RootIdentity(), identity );
                env->addVisibilityRule( identity, locVarsIdentity );

                auto result = Compiler::LoadAndExecuteFile( env, filename, locVarsIdentity,
                    GetValueType< uint32_t >(), ToValue< uint32_t >( 0 ) );

                if( !result )
                    return ToValue< uint32_t >( 0 );







|




|







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
            } );

        RegisterBuiltinFunc< uint32_t ( string ) >( e, "ExecuteFile"_sid,
            [pEnv]( const string& filename ) -> Value
            {
                // For now generate an unique identity for the file to execute. Later we might want to
                // pass an identity as parameters as a wrapped term.
                auto identity = AppendToVectorTerm( RootG0Identity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );
                auto locVarsIdentity = AppendToVectorTerm( identity, TSID( locvars ) );

                auto env = pEnv.lock();
                env->addVisibilityRule( builtins::RootG0Identity(), identity );
                env->addVisibilityRule( identity, locVarsIdentity );

                auto result = Compiler::LoadAndExecuteFile( env, filename, locVarsIdentity,
                    GetValueType< uint32_t >(), ToValue< uint32_t >( 0 ) );

                if( !result )
                    return ToValue< uint32_t >( 0 );
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
                    DiagnosticsManager::GetInstance().emitErrorMessage( params.locationId(),
                        "#CompileFileToFunction: template parameter lists are not supported.", 0 );
                    return PoisonValue();
                }

                // TODO at some point we'll want to pass the base identity to use as a param but
                // let's wait and see how the module and namespace stuff pans out first
                sema::Context localC( pEnv.lock(), builtins::RootIdentity(), ValueToEIR( rt ) );
                auto ftype = BuildFuncType( localC, rt, params );
                if( !ftype )
                    return PoisonValue();

                auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );
                c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );

                auto locVarsIdentity = AppendToVectorTerm( funcIdentity, TSID( locvars ) );
                c.env()->addVisibilityRule( funcIdentity, locVarsIdentity );

                auto func = BuildFunc( localC, *ftype, funcIdentity, params, nullptr, c );
                const auto& pFuncCIR = func.cir();








|




|

|







201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
                    DiagnosticsManager::GetInstance().emitErrorMessage( params.locationId(),
                        "#CompileFileToFunction: template parameter lists are not supported.", 0 );
                    return PoisonValue();
                }

                // TODO at some point we'll want to pass the base identity to use as a param but
                // let's wait and see how the module and namespace stuff pans out first
                sema::Context localC( pEnv.lock(), builtins::RootG0Identity(), ValueToEIR( rt ) );
                auto ftype = BuildFuncType( localC, rt, params );
                if( !ftype )
                    return PoisonValue();

                auto funcIdentity = AppendToVectorTerm( builtins::RootG0Identity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );
                c.env()->addVisibilityRule( builtins::RootG0Identity(), funcIdentity );

                auto locVarsIdentity = AppendToVectorTerm( funcIdentity, TSID( locvars ) );
                c.env()->addVisibilityRule( funcIdentity, locVarsIdentity );

                auto func = BuildFunc( localC, *ftype, funcIdentity, params, nullptr, c );
                const auto& pFuncCIR = func.cir();

Added bs/g0api/extensibility/extensibility.h.




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef GOOSE_G0_API_EXTENSIBILITY_H
#define GOOSE_G0_API_EXTENSIBILITY_H

namespace goose::g0api
{
    extern void SetupTermExtensibilityFuncs( Env& e );

    static inline void SetupApiExtensibility( Env& e )
    {
        SetupTermExtensibilityFuncs( e );
    }
}

#endif
Added bs/g0api/extensibility/term.cpp.








































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "g0api/g0api.h"
#include "eir/eir.h"
#include "parse/parse.h"
#include "builtins/helpers.h"

using namespace goose;
using namespace goose::parse;
using namespace goose::builtins;

namespace goose::g0api
{
    void SetupTermExtensibilityFuncs( Env& e )
    {
        // Constants.
        DefineConstant( e, "DelimiterOpenParen"_sid, ValueToEIR( ToValue( BigInt::FromU32( static_cast< uint32_t >( Delimiter::OpenParen ) ) ) ) );
        DefineConstant( e, "DelimiterOpenBrace"_sid, ValueToEIR( ToValue( BigInt::FromU32( static_cast< uint32_t >( Delimiter::OpenBrace ) ) ) ) );
        DefineConstant( e, "DelimiterOpenBracket"_sid, ValueToEIR( ToValue( BigInt::FromU32( static_cast< uint32_t >( Delimiter::OpenBracket ) ) ) ) );
        DefineConstant( e, "DelimiterCloseParen"_sid, ValueToEIR( ToValue( BigInt::FromU32( static_cast< uint32_t >( Delimiter::CloseParen ) ) ) ) );
        DefineConstant( e, "DelimiterCloseBrace"_sid, ValueToEIR( ToValue( BigInt::FromU32( static_cast< uint32_t >( Delimiter::CloseBrace ) ) ) ) );
        DefineConstant( e, "DelimiterCloseBracket"_sid, ValueToEIR( ToValue( BigInt::FromU32( static_cast< uint32_t >( Delimiter::CloseBracket ) ) ) ) );

        // These must match the order of the Term variant.
        DefineConstant( e, "TermTypeUInt32"_sid, ValueToEIR( ToValue( BigInt::FromU32( 0 ) ) ) );
        DefineConstant( e, "TermTypeLocationId"_sid, ValueToEIR( ToValue( BigInt::FromU32( 1 ) ) ) );
        DefineConstant( e, "TermTypeString"_sid, ValueToEIR( ToValue( BigInt::FromU32( 2 ) ) ) );
        DefineConstant( e, "TermTypeStringId"_sid, ValueToEIR( ToValue( BigInt::FromU32( 3 ) ) ) );
        DefineConstant( e, "TermTypeDelimiter"_sid, ValueToEIR( ToValue( BigInt::FromU32( 4 ) ) ) );
        DefineConstant( e, "TermTypeHole"_sid, ValueToEIR( ToValue( BigInt::FromU32( 5 ) ) ) );
        DefineConstant( e, "TermTypeAnyTerm"_sid, ValueToEIR( ToValue( BigInt::FromU32( 6 ) ) ) );
        DefineConstant( e, "TermTypeVecOfLength"_sid, ValueToEIR( ToValue( BigInt::FromU32( 7 ) ) ) );
        DefineConstant( e, "TermTypeVec"_sid, ValueToEIR( ToValue( BigInt::FromU32( 8 ) ) ) );
        DefineConstant( e, "TermTypeBigInt"_sid, ValueToEIR( ToValue( BigInt::FromU32( 9 ) ) ) );
        DefineConstant( e, "TermTypeFixedInt"_sid, ValueToEIR( ToValue( BigInt::FromU32( 10 ) ) ) );
        DefineConstant( e, "TermTypeInternal "_sid, ValueToEIR( ToValue( BigInt::FromU32( 11 ) ) ) );
    }
}
Changes to bs/g0api/g0api.h.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
{
    using namespace sema;
    using namespace builtins;
}

#include "support/support.h"
#include "cgapi/cgapi.h"


namespace goose::g0api
{
    extern void SetupApiString( Env& e );
    extern void SetupApiCompiler( Env& e );

    static inline void SetupG0Api( Env& e )
    {
        SetupApiString( e );
        SetupApiCompiler( e );
        SetupApiSupport( e );
        SetupApiCodeGen( e );

    }
}

#endif







>












>




8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
    using namespace sema;
    using namespace builtins;
}

#include "support/support.h"
#include "cgapi/cgapi.h"
#include "extensibility/extensibility.h"

namespace goose::g0api
{
    extern void SetupApiString( Env& e );
    extern void SetupApiCompiler( Env& e );

    static inline void SetupG0Api( Env& e )
    {
        SetupApiString( e );
        SetupApiCompiler( e );
        SetupApiSupport( e );
        SetupApiCodeGen( e );
        SetupApiExtensibility( e );
    }
}

#endif
Changes to bs/g0api/meson.build.
1
2
3
4
5
6
7
8
9
10
11


12
13
14
15
goose_g0api = library( 'goose-g0api',
    'string.cpp',
    'compiler.cpp',

    'support/cast.cpp',
    'support/verification.cpp',

    'cgapi/module.cpp',
    'cgapi/mangle.cpp',
    'cgapi/func.cpp',
    'cgapi/linker.cpp',



    include_directories: bsinc,
    dependencies: fmt_dep
)











>
>




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
goose_g0api = library( 'goose-g0api',
    'string.cpp',
    'compiler.cpp',

    'support/cast.cpp',
    'support/verification.cpp',

    'cgapi/module.cpp',
    'cgapi/mangle.cpp',
    'cgapi/func.cpp',
    'cgapi/linker.cpp',

    'extensibility/term.cpp',

    include_directories: bsinc,
    dependencies: fmt_dep
)
Changes to bs/parse/func.cpp.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    return true;
}

bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
    auto d = FromValue< Decl >( decl );

    if( !parseFuncType( *ValueFromEIR( d->type() ), paramsDecl ) )
        return false;

    const auto& c = context();

    auto funcIdentity = TakeVectorTerm( c.identity(), VecSize( c.identity() ) - 1 );
    get< pvec >( funcIdentity )->terms().back() = TERM( d->name() );








|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    return true;
}

bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
    auto d = FromValue< Decl >( decl );

    if( !parseFuncType( *EIRToValue( d->type() ), paramsDecl ) )
        return false;

    const auto& c = context();

    auto funcIdentity = TakeVectorTerm( c.identity(), VecSize( c.identity() ) - 1 );
    get< pvec >( funcIdentity )->terms().back() = TERM( d->name() );

Changes to bs/parse/overload.cpp.
83
84
85
86
87
88
89
90
91
92
                Val< ptr< void > >(),
                SubTerm()
            )
        );
        assert( decomp );
        auto&& [pOvlSet, callee] = *decomp;

        return Overload( static_pointer_cast< sema::OverloadSet >( pOvlSet ), *ValueFromEIR( *Unquote( callee ) ) );
    }
}







|


83
84
85
86
87
88
89
90
91
92
                Val< ptr< void > >(),
                SubTerm()
            )
        );
        assert( decomp );
        auto&& [pOvlSet, callee] = *decomp;

        return Overload( static_pointer_cast< sema::OverloadSet >( pOvlSet ), *EIRToValue( *Unquote( callee ) ) );
    }
}
Changes to bs/parse/parser.cpp.
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    return parsePrefix( strid, prec );
}

bool Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromEIR( t.first );
    if( !val )
        return false;

    if( val->isPoison() )
        DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

    // If the term is a prefix rule value, invoke its parsePrefix() function.







|







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    return parsePrefix( strid, prec );
}

bool Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = EIRToValue( t.first );
    if( !val )
        return false;

    if( val->isPoison() )
        DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

    // If the term is a prefix rule value, invoke its parsePrefix() function.
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

    m_resolver->consume();
    return ( *rule )->parsePrefix( *this, t.second, prec );
}

optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
    auto val = ValueFromEIR( t );
    if( !val )
        return nullopt;

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
    {
        if( !peekLastValue() )
            return nullopt;







|







254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

    m_resolver->consume();
    return ( *rule )->parsePrefix( *this, t.second, prec );
}

optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
    auto val = EIRToValue( t );
    if( !val )
        return nullopt;

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
    {
        if( !peekLastValue() )
            return nullopt;
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
    return ( *rule )->getPrecedence( *this );
}

bool Parser::parseInfix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromEIR( t.first );
    if( !val )
        return false;

    if( val->isPoison() )
        DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

    if( val->type() == GetValueType< ptr< OverloadSet > >() )







|







284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
    return ( *rule )->getPrecedence( *this );
}

bool Parser::parseInfix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = EIRToValue( t.first );
    if( !val )
        return false;

    if( val->isPoison() )
        DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
Changes to bs/parse/tfunc.cpp.
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    return true;
}

bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
    auto d = FromValue< TNamedDecl >( tnamedDecl );

    if( !parseTFuncType( *ValueFromEIR( d->type() ), paramsDecl ) )
        return false;

    const auto& c = context();

    auto tfuncIdentity = TakeVectorTerm( c.identity(), VecSize( c.identity() ) - 1 );
    get< pvec >( tfuncIdentity )->terms().back() = TERM( d->name() );








|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    return true;
}

bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
    auto d = FromValue< TNamedDecl >( tnamedDecl );

    if( !parseTFuncType( *EIRToValue( d->type() ), paramsDecl ) )
        return false;

    const auto& c = context();

    auto tfuncIdentity = TakeVectorTerm( c.identity(), VecSize( c.identity() ) - 1 );
    get< pvec >( tfuncIdentity )->terms().back() = TERM( d->name() );

Changes to bs/sema/lower.cpp.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            return nullopt;

        return result;
    }

    optional< Value > LowerConstantForRuntime( const Context& c, const Value& val )
    {
        if( val.type() == GetValueType< bool >() || IsRuntimeType( *ValueFromEIR( val.type() ) ) )
            return val;

        DiagnosticsContext dc( val.locationId(), "When invoking LowerConstantForRuntime." );
        auto result = InvokeOverloadSet( c, c.env()->extLowerConstantForRuntime(), AppendToTuple( EmptyTuple(), val ) );
        if( result.isPoison() || !IsRuntimeType( *ValueFromEIR( result.type() ) ) )
            return nullopt;

        return result;
    }

    optional< Value > LowerTypeForVerification( const Context& c, const Value& type )
    {







|




|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
            return nullopt;

        return result;
    }

    optional< Value > LowerConstantForRuntime( const Context& c, const Value& val )
    {
        if( val.type() == GetValueType< bool >() || IsRuntimeType( *EIRToValue( val.type() ) ) )
            return val;

        DiagnosticsContext dc( val.locationId(), "When invoking LowerConstantForRuntime." );
        auto result = InvokeOverloadSet( c, c.env()->extLowerConstantForRuntime(), AppendToTuple( EmptyTuple(), val ) );
        if( result.isPoison() || !IsRuntimeType( *EIRToValue( result.type() ) ) )
            return nullopt;

        return result;
    }

    optional< Value > LowerTypeForVerification( const Context& c, const Value& type )
    {
Changes to bs/verify/call.cpp.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        // Inject the arguments in the context.
        // They will be picked up by getVars instructions when refered to
        // by the verification conditions.
        uint32_t index = 0;

        ForEachInVectorTerm( instr.args(), [&]( auto&& t )
        {
            auto arg = *ValueFromEIR( t );

            if( auto zv = BuildZ3ExprFromValue( b, arg ) )
                cb.setVar( index++, move( *zv ) );

            return true;
        } );








|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        // Inject the arguments in the context.
        // They will be picked up by getVars instructions when refered to
        // by the verification conditions.
        uint32_t index = 0;

        ForEachInVectorTerm( instr.args(), [&]( auto&& t )
        {
            auto arg = *EIRToValue( t );

            if( auto zv = BuildZ3ExprFromValue( b, arg ) )
                cb.setVar( index++, move( *zv ) );

            return true;
        } );

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
        if( retExpr )
            cb.setPlaceholder( "@result"_sid, retExpr->expr );

        // Check preconditions.
        const auto& preConds = fvi->preConditions();
        ForEachInVectorTerm( preConds, [&]( auto&& t )
        {
            auto val = *ValueFromEIR( t );

            if( auto zv = BuildZ3ExprFromValue( cb, val ) )
            {
                DiagnosticsContext dc( instr.func().locationId(), "At this call." );
                b.checkAssertion( zv->expr, val.locationId() );
            }

            return true;
        } );

        // Add the return type's predicates as assumptions.
        ForEachPredicate( cb, ft.returnType(), retExpr->expr, [&]( auto&& z3expr, auto locId )
        {
            b.assume( z3expr );
        } );

        // Add postconditions as assumptions.
        const auto& postConds = fvi->postConditions();
        ForEachInVectorTerm( postConds, [&]( auto&& t )
        {
            if( auto zv = BuildZ3ExprFromValue( cb, *ValueFromEIR( t ) ) )
                b.assume( zv->expr );
            return true;
        } );

        return retExpr;
    }
}







|




















|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
        if( retExpr )
            cb.setPlaceholder( "@result"_sid, retExpr->expr );

        // Check preconditions.
        const auto& preConds = fvi->preConditions();
        ForEachInVectorTerm( preConds, [&]( auto&& t )
        {
            auto val = *EIRToValue( t );

            if( auto zv = BuildZ3ExprFromValue( cb, val ) )
            {
                DiagnosticsContext dc( instr.func().locationId(), "At this call." );
                b.checkAssertion( zv->expr, val.locationId() );
            }

            return true;
        } );

        // Add the return type's predicates as assumptions.
        ForEachPredicate( cb, ft.returnType(), retExpr->expr, [&]( auto&& z3expr, auto locId )
        {
            b.assume( z3expr );
        } );

        // Add postconditions as assumptions.
        const auto& postConds = fvi->postConditions();
        ForEachInVectorTerm( postConds, [&]( auto&& t )
        {
            if( auto zv = BuildZ3ExprFromValue( cb, *EIRToValue( t ) ) )
                b.assume( zv->expr );
            return true;
        } );

        return retExpr;
    }
}
Changes to bs/verify/comptime.cpp.
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        // by the verification conditions.
        uint32_t index = 0;

        bool eagerEvalFailed = false;

        ForEachInVectorTerm( instr.args(), [&]( auto&& t )
        {
            auto arg = ValueFromEIR( t );

            if( !arg->isConstant() )
            {
                execute::VM vm;
                arg = execute::Evaluate( *arg, vm );

                if( !arg->isConstant() )







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        // by the verification conditions.
        uint32_t index = 0;

        bool eagerEvalFailed = false;

        ForEachInVectorTerm( instr.args(), [&]( auto&& t )
        {
            auto arg = EIRToValue( t );

            if( !arg->isConstant() )
            {
                execute::VM vm;
                arg = execute::Evaluate( *arg, vm );

                if( !arg->isConstant() )
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
            return true;
        } );

        // Check preconditions.
        const auto& preConds = fvi->preConditions();
        ForEachInVectorTerm( preConds, [&]( auto&& t )
        {
            auto val = *ValueFromEIR( t );

            if( auto zv = BuildZ3ExprFromValue( b, val ) )
            {
                DiagnosticsContext dc( instr.func().locationId(), "At this compilation-time call." );
                b.checkAssertion( zv->expr, val.locationId() );
            }

            return true;
        } );

        return !b.hasCheckFailed();
    }
}







|













158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
            return true;
        } );

        // Check preconditions.
        const auto& preConds = fvi->preConditions();
        ForEachInVectorTerm( preConds, [&]( auto&& t )
        {
            auto val = *EIRToValue( t );

            if( auto zv = BuildZ3ExprFromValue( b, val ) )
            {
                DiagnosticsContext dc( instr.func().locationId(), "At this compilation-time call." );
                b.checkAssertion( zv->expr, val.locationId() );
            }

            return true;
        } );

        return !b.hasCheckFailed();
    }
}
Changes to bs/verify/condition.cpp.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

bool Condition::addConditionsList( const pvec& assList )
{
    bool success = true;

    ForEachInVectorTerm( assList, [&]( auto&& t )
    {
        auto val = *ValueFromEIR( t );
        if( val.isPoison() )
        {
            success = false;
            return false;
        }

        if( val.type() != GetValueType< bool >() )







|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

bool Condition::addConditionsList( const pvec& assList )
{
    bool success = true;

    ForEachInVectorTerm( assList, [&]( auto&& t )
    {
        auto val = *EIRToValue( t );
        if( val.isPoison() )
        {
            success = false;
            return false;
        }

        if( val.type() != GetValueType< bool >() )
Changes to bs/verify/func.cpp.
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

                // Add assumptions of the function's requirements
                const auto& reqs = m_func->type().verifInfos()->preConditions();
                ForEachInVectorTerm( reqs, [&]( auto&& t )
                {
                    // Don't do any error handling here, it should already have been taken care of
                    // by the condition verifier.
                    if( auto zv = BuildZ3ExprFromValue( m_builder, *ValueFromEIR( t ) ) )
                        m_builder.assume( zv->expr );

                    return true;
                } );
            }

            bool result = buildZ3Expressions( *m_cfg->entryBB(), nullptr );







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

                // Add assumptions of the function's requirements
                const auto& reqs = m_func->type().verifInfos()->preConditions();
                ForEachInVectorTerm( reqs, [&]( auto&& t )
                {
                    // Don't do any error handling here, it should already have been taken care of
                    // by the condition verifier.
                    if( auto zv = BuildZ3ExprFromValue( m_builder, *EIRToValue( t ) ) )
                        m_builder.assume( zv->expr );

                    return true;
                } );
            }

            bool result = buildZ3Expressions( *m_cfg->entryBB(), nullptr );
Changes to bs/verify/helpers.inl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef GOOSE_HELPERS_INL
#define GOOSE_HELPERS_INL

#include "builtins/helpers.h"

namespace goose::verify
{
    template< typename F >
    void ForEachPredicate( Builder& b, const Term& t, const z3::expr& valExpr, F&& func )
    {
        auto type = *ValueFromEIR( t );

        auto optTypePreds = builtins::GetTypePredicates( type );
        if( !optTypePreds || !*optTypePreds )
            return;

        auto& tp = **optTypePreds;
        const auto* prevValPH = b.retrievePlaceholder( "@val"_sid );
        b.setPlaceholder( "@val"_sid, valExpr );

        ForEachInVectorTerm( tp.m_predicates, [&]( auto&& p )
        {
            auto predVal = *ValueFromEIR( p );
            if( auto zv = BuildZ3ExprFromValue( b, predVal ) )
                func( zv->expr, predVal.locationId() );

            return true;
        } );

        if( prevValPH )










|











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef GOOSE_HELPERS_INL
#define GOOSE_HELPERS_INL

#include "builtins/helpers.h"

namespace goose::verify
{
    template< typename F >
    void ForEachPredicate( Builder& b, const Term& t, const z3::expr& valExpr, F&& func )
    {
        auto type = *EIRToValue( t );

        auto optTypePreds = builtins::GetTypePredicates( type );
        if( !optTypePreds || !*optTypePreds )
            return;

        auto& tp = **optTypePreds;
        const auto* prevValPH = b.retrievePlaceholder( "@val"_sid );
        b.setPlaceholder( "@val"_sid, valExpr );

        ForEachInVectorTerm( tp.m_predicates, [&]( auto&& p )
        {
            auto predVal = *EIRToValue( p );
            if( auto zv = BuildZ3ExprFromValue( b, predVal ) )
                func( zv->expr, predVal.locationId() );

            return true;
        } );

        if( prevValPH )
Changes to bs/verify/storage.cpp.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
        if( !tinfo )
            return nullopt;

        // The only aggregate type that we handle for now are tuples.
        // TODO: arrays
        auto elemType = GetTupleTypeElement( val->type, s.memberIndex() );
        auto elemExpr = tinfo->proj( val->expr, s.memberIndex() );
        return Z3Val{ move( elemExpr ), *ValueFromEIR( elemType ) };
    }

    using SelectPath = llvm::SmallVector< uint32_t, 8 >;
    optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const SelectPath& path, uint32_t index, Z3Val&& valToStore )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( aggregate.type ) );
        if( !tinfo )







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
        if( !tinfo )
            return nullopt;

        // The only aggregate type that we handle for now are tuples.
        // TODO: arrays
        auto elemType = GetTupleTypeElement( val->type, s.memberIndex() );
        auto elemExpr = tinfo->proj( val->expr, s.memberIndex() );
        return Z3Val{ move( elemExpr ), *EIRToValue( elemType ) };
    }

    using SelectPath = llvm::SmallVector< uint32_t, 8 >;
    optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const SelectPath& path, uint32_t index, Z3Val&& valToStore )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( aggregate.type ) );
        if( !tinfo )
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
            if( i == elemIndex )
            {
                // If we didn't reach the end of the path yet, recurse.
                // Otherwise, it means we finally reached the nested member that we wanted to modify,
                // so push the new value.
                if( index > 0 )
                {
                    auto newElem = ModifyAggregate( b, Z3Val{ move( elemExpr ), *ValueFromEIR( elemType ) }, path, --index, move( valToStore ) );
                    if( !newElem )
                        return nullopt;

                    args.push_back( move( *newElem ) );
                }
                else
                    args.push_back( valToStore.expr );







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
            if( i == elemIndex )
            {
                // If we didn't reach the end of the path yet, recurse.
                // Otherwise, it means we finally reached the nested member that we wanted to modify,
                // so push the new value.
                if( index > 0 )
                {
                    auto newElem = ModifyAggregate( b, Z3Val{ move( elemExpr ), *EIRToValue( elemType ) }, path, --index, move( valToStore ) );
                    if( !newElem )
                        return nullopt;

                    args.push_back( move( *newElem ) );
                }
                else
                    args.push_back( valToStore.expr );
Changes to bs/verify/terminator.cpp.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
        const auto& postConds = m_func->type().verifInfos()->postConditions();
        bool success = true;

        ForEachInVectorTerm( postConds, [&]( auto&& t )
        {
            // Don't do any error handling here, it should already have been taken care of
            // by the condition verifier.
            auto cond = *ValueFromEIR( t );

            if( auto zv = BuildZ3ExprFromValue( cb, cond ) )
            {
                bool succ = false;

                // TODO: we don't have a useful location here in the case of a return from a void func.
                // we'll have to add it to the ret statement. The case can only happen when checking post conditions







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
        const auto& postConds = m_func->type().verifInfos()->postConditions();
        bool success = true;

        ForEachInVectorTerm( postConds, [&]( auto&& t )
        {
            // Don't do any error handling here, it should already have been taken care of
            // by the condition verifier.
            auto cond = *EIRToValue( t );

            if( auto zv = BuildZ3ExprFromValue( cb, cond ) )
            {
                bool succ = false;

                // TODO: we don't have a useful location here in the case of a return from a void func.
                // we'll have to add it to the ret statement. The case can only happen when checking post conditions
Changes to bs/verify/type.cpp.
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    }

    return nullopt;
}

optional< TypeInfo > TypeCache::CreateTypeInfo( const sema::Context& c, const Term& type )
{
    auto typeVal = *ValueFromEIR( type );

    auto tinfo = CreateTypeInfoForBasicType( c, typeVal );
    if( tinfo )
        return tinfo;

    // The only non aggregate type that we handle at the moment are tuples.
    // Other higher level types such as structs and classes need to be lowered







|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    }

    return nullopt;
}

optional< TypeInfo > TypeCache::CreateTypeInfo( const sema::Context& c, const Term& type )
{
    auto typeVal = *EIRToValue( type );

    auto tinfo = CreateTypeInfoForBasicType( c, typeVal );
    if( tinfo )
        return tinfo;

    // The only non aggregate type that we handle at the moment are tuples.
    // Other higher level types such as structs and classes need to be lowered
Changes to bs/verify/value.cpp.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
            return nullopt;

        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), loweredVal->type() );
        if( !tinfo )
            return nullopt;

        auto zexpr = tinfo->build( b, *loweredVal );
        return Z3Val { move( zexpr ), *ValueFromEIR( val.type() ) };
    }

    optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Value& type, const string& name )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( type ) );
        if( !tinfo )
            return nullopt;

        assert( tinfo->sort );
        return Z3Val { GetZ3Context().constant( name.c_str(), *tinfo->sort ), type };
    }

    optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Term& type, const string& name )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), type );
        if( !tinfo )
            return nullopt;

        assert( tinfo->sort );
        return Z3Val { GetZ3Context().constant( name.c_str(), *tinfo->sort ), *ValueFromEIR( type ) };
    }

    z3::expr GetAsBitVec( const z3::expr& expr, const Value& type )
    {
        if( expr.is_bv() )
            return expr;








|



















|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
            return nullopt;

        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), loweredVal->type() );
        if( !tinfo )
            return nullopt;

        auto zexpr = tinfo->build( b, *loweredVal );
        return Z3Val { move( zexpr ), *EIRToValue( val.type() ) };
    }

    optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Value& type, const string& name )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( type ) );
        if( !tinfo )
            return nullopt;

        assert( tinfo->sort );
        return Z3Val { GetZ3Context().constant( name.c_str(), *tinfo->sort ), type };
    }

    optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Term& type, const string& name )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), type );
        if( !tinfo )
            return nullopt;

        assert( tinfo->sort );
        return Z3Val { GetZ3Context().constant( name.c_str(), *tinfo->sort ), *EIRToValue( type ) };
    }

    z3::expr GetAsBitVec( const z3::expr& expr, const Value& type )
    {
        if( expr.is_bv() )
            return expr;

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
            return nullopt;

        auto rhs = BuildZ3ExprFromValue( b, instr.rhs() );
        if( !rhs )
            return nullopt;

        if( lhs->expr.get_sort().sort_kind() == rhs->expr.get_sort().sort_kind() )
            return Z3Val{ func( lhs->expr, rhs->expr, lhs->type ), *ValueFromEIR( GetValueType< bool >() ) };

        // If we are trying to do an operation on a mix of bitvec and int,
        // convert the int to a bitvec first.
        if( lhs->expr.is_bv() )
        {
            assert( rhs->expr.is_int() );
            return Z3Val{ func( lhs->expr, GetAsBitVec( *rhs ), lhs->type ), *ValueFromEIR( GetValueType< bool >() ) };
        }
        else
        {
            assert( lhs->expr.is_int() );
            return Z3Val{ func( GetAsBitVec( *lhs ), rhs->expr, lhs->type ), *ValueFromEIR( GetValueType< bool >() ) };
        }

        return nullopt;
    }

    template< typename T >
    optional< Z3Val > BuildZ3Op( Builder& b, const T& instr )







|






|




|







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
            return nullopt;

        auto rhs = BuildZ3ExprFromValue( b, instr.rhs() );
        if( !rhs )
            return nullopt;

        if( lhs->expr.get_sort().sort_kind() == rhs->expr.get_sort().sort_kind() )
            return Z3Val{ func( lhs->expr, rhs->expr, lhs->type ), *EIRToValue( GetValueType< bool >() ) };

        // If we are trying to do an operation on a mix of bitvec and int,
        // convert the int to a bitvec first.
        if( lhs->expr.is_bv() )
        {
            assert( rhs->expr.is_int() );
            return Z3Val{ func( lhs->expr, GetAsBitVec( *rhs ), lhs->type ), *EIRToValue( GetValueType< bool >() ) };
        }
        else
        {
            assert( lhs->expr.is_int() );
            return Z3Val{ func( GetAsBitVec( *lhs ), rhs->expr, lhs->type ), *EIRToValue( GetValueType< bool >() ) };
        }

        return nullopt;
    }

    template< typename T >
    optional< Z3Val > BuildZ3Op( Builder& b, const T& instr )
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
        return nullopt;
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const Placeholder& instr )
    {
        const auto* expr = b.retrievePlaceholder( instr.name() );
        if( expr )
            return Z3Val{ *expr, *ValueFromEIR( instr.type() ) };

        return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const cir::Instruction& instr )
    {
        return visit( [&]( auto&& e )







|







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
        return nullopt;
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const Placeholder& instr )
    {
        const auto* expr = b.retrievePlaceholder( instr.name() );
        if( expr )
            return Z3Val{ *expr, *EIRToValue( instr.type() ) };

        return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const cir::Instruction& instr )
    {
        return visit( [&]( auto&& e )